Skip to content

Commit a53186e

Browse files
committed
Sema: Allow optional promotion of tuple patterns
1 parent 2bfd9ee commit a53186e

File tree

10 files changed

+655
-4
lines changed

10 files changed

+655
-4
lines changed

include/swift/Sema/Constraint.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ enum class ConstraintKind : char {
158158
/// The first type is an optional type whose object type is the second
159159
/// type, preserving lvalue-ness.
160160
OptionalObject,
161+
/// The first type is an optional of non-negative depth of the second type,
162+
/// ignoring lvalueness (because the constraint is currently applied only to
163+
/// pattern types, which are always rvalue). For example, given a RHS of
164+
/// 'Int', a LHS of 'Int' or 'Int??' would satisfy this constraint.
165+
EqualOrOptional,
161166
/// The first type is the same function type as the second type, but
162167
/// made @escaping.
163168
EscapableFunctionOf,
@@ -696,6 +701,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
696701
case ConstraintKind::DynamicCallableApplicableFunction:
697702
case ConstraintKind::BindOverload:
698703
case ConstraintKind::OptionalObject:
704+
case ConstraintKind::EqualOrOptional:
699705
case ConstraintKind::OneWayEqual:
700706
case ConstraintKind::OneWayBindParam:
701707
case ConstraintKind::DefaultClosureType:

include/swift/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4704,6 +4704,12 @@ class ConstraintSystem {
47044704
TypeMatchOptions flags,
47054705
ConstraintLocatorBuilder locator);
47064706

4707+
/// Attempt to simplify an equal-or-optional constraint.
4708+
SolutionKind
4709+
simplifyEqualOrOptionalConstraint(Type first, Type second,
4710+
TypeMatchOptions flags,
4711+
ConstraintLocatorBuilder locator);
4712+
47074713
/// Attempt to simplify the BridgingConversion constraint.
47084714
SolutionKind simplifyBridgingConstraint(Type type1,
47094715
Type type2,

lib/Sema/CSBindings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,7 @@ void PotentialBindings::infer(Constraint *constraint) {
14401440
case ConstraintKind::ArgumentConversion:
14411441
case ConstraintKind::OperatorArgumentConversion:
14421442
case ConstraintKind::OptionalObject:
1443+
case ConstraintKind::EqualOrOptional:
14431444
case ConstraintKind::UnresolvedMemberChainBase: {
14441445
auto binding = inferFromRelational(constraint);
14451446
if (!binding)

lib/Sema/CSGen.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2701,7 +2701,24 @@ namespace {
27012701
tupleTypeElts.push_back(TupleTypeElt(eltTy, tupleElt.getLabel()));
27022702
}
27032703

2704-
return setType(TupleType::get(tupleTypeElts, CS.getASTContext()));
2704+
Type patternTy = TupleType::get(tupleTypeElts, CS.getASTContext());
2705+
2706+
// 1. Allow optional promotion only when the matching is conditional,
2707+
// i.e., not in pattern binding declarations.
2708+
// 2. A single-element tuple can only mean that we are matching the
2709+
// payload of an enum case without splatting, in which case optional
2710+
// promotion is irrelevant.
2711+
if (!patternBinding && tupleTypeElts.size() > 1) {
2712+
Type tyVar = CS.createTypeVariable(CS.getConstraintLocator(locator),
2713+
TVO_CanBindToNoEscape);
2714+
CS.addConstraint(
2715+
ConstraintKind::EqualOrOptional, tyVar, patternTy,
2716+
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2717+
2718+
patternTy = tyVar;
2719+
}
2720+
2721+
return setType(patternTy);
27052722
}
27062723

27072724
case PatternKind::OptionalSome: {

lib/Sema/CSSimplify.cpp

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2271,6 +2271,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
22712271
case ConstraintKind::KeyPathApplication:
22722272
case ConstraintKind::LiteralConformsTo:
22732273
case ConstraintKind::OptionalObject:
2274+
case ConstraintKind::EqualOrOptional:
22742275
case ConstraintKind::SelfObjectOfProtocol:
22752276
case ConstraintKind::UnresolvedValueMember:
22762277
case ConstraintKind::ValueMember:
@@ -2633,6 +2634,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
26332634
case ConstraintKind::KeyPathApplication:
26342635
case ConstraintKind::LiteralConformsTo:
26352636
case ConstraintKind::OptionalObject:
2637+
case ConstraintKind::EqualOrOptional:
26362638
case ConstraintKind::SelfObjectOfProtocol:
26372639
case ConstraintKind::UnresolvedValueMember:
26382640
case ConstraintKind::ValueMember:
@@ -3140,6 +3142,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
31403142
case ConstraintKind::KeyPathApplication:
31413143
case ConstraintKind::LiteralConformsTo:
31423144
case ConstraintKind::OptionalObject:
3145+
case ConstraintKind::EqualOrOptional:
31433146
case ConstraintKind::SelfObjectOfProtocol:
31443147
case ConstraintKind::UnresolvedValueMember:
31453148
case ConstraintKind::ValueMember:
@@ -6687,6 +6690,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
66876690
case ConstraintKind::KeyPathApplication:
66886691
case ConstraintKind::LiteralConformsTo:
66896692
case ConstraintKind::OptionalObject:
6693+
case ConstraintKind::EqualOrOptional:
66906694
case ConstraintKind::SelfObjectOfProtocol:
66916695
case ConstraintKind::UnresolvedValueMember:
66926696
case ConstraintKind::ValueMember:
@@ -8811,6 +8815,60 @@ ConstraintSystem::simplifyOptionalObjectConstraint(
88118815
return SolutionKind::Solved;
88128816
}
88138817

8818+
ConstraintSystem::SolutionKind
8819+
ConstraintSystem::simplifyEqualOrOptionalConstraint(
8820+
Type first, Type second, TypeMatchOptions flags,
8821+
ConstraintLocatorBuilder locator) {
8822+
// Reify all the type variables we can.
8823+
first = getFixedTypeRecursive(first, flags, /*wantRValue=*/false);
8824+
second = getFixedTypeRecursive(second, flags, /*wantRValue=*/false);
8825+
8826+
assert(!first->hasLValueType() && !second->hasLValueType() &&
8827+
"Unexpected lvalue; constraint operand is not a pattern type?");
8828+
8829+
if (first->isEqual(second)) {
8830+
return SolutionKind::Solved;
8831+
}
8832+
8833+
// Unwrap both types simultaneously until one of them is no longer optional.
8834+
while (true) {
8835+
if (auto firstObject = first->getOptionalObjectType()) {
8836+
if (auto secondObject = second->getOptionalObjectType()) {
8837+
first = firstObject;
8838+
second = secondObject;
8839+
continue;
8840+
}
8841+
}
8842+
8843+
break;
8844+
}
8845+
8846+
const Type firstUnwrapped = first->lookThroughAllOptionalTypes();
8847+
8848+
// At this point at most one of the two types is a known optional. The
8849+
// constraint can be reduced to an equation between the fully unwrapped LHS
8850+
// and the RHS — and thus solved — if the following conditions are met:
8851+
// 1. The fully unwrapped LHS is not a type variable.
8852+
// 2. Either the LHS is not optional to begin with, or the RHS is not a
8853+
// type variable.
8854+
8855+
if (firstUnwrapped->isTypeVariableOrMember() ||
8856+
(first->isOptional() && second->isTypeVariableOrMember())) {
8857+
if (!flags.contains(TMF_GenerateConstraints)) {
8858+
return SolutionKind::Unsolved;
8859+
}
8860+
8861+
addUnsolvedConstraint(
8862+
Constraint::create(*this, ConstraintKind::EqualOrOptional, first,
8863+
second, getConstraintLocator(locator)));
8864+
return SolutionKind::Solved;
8865+
}
8866+
8867+
addConstraint(ConstraintKind::Bind, firstUnwrapped, second, locator);
8868+
8869+
return SolutionKind::Solved;
8870+
}
8871+
88148872
ConstraintSystem::SolutionKind
88158873
ConstraintSystem::simplifyBindTupleOfFunctionParamsConstraint(
88168874
Type first, Type second, TypeMatchOptions flags,
@@ -14457,6 +14515,9 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
1445714515
case ConstraintKind::OptionalObject:
1445814516
return simplifyOptionalObjectConstraint(first, second, subflags, locator);
1445914517

14518+
case ConstraintKind::EqualOrOptional:
14519+
return simplifyEqualOrOptionalConstraint(first, second, subflags, locator);
14520+
1446014521
case ConstraintKind::Defaultable:
1446114522
return simplifyDefaultableConstraint(first, second, subflags, locator);
1446214523

@@ -15003,7 +15064,12 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1500315064
constraint.getSecondType(),
1500415065
/*flags*/ None,
1500515066
constraint.getLocator());
15006-
15067+
15068+
case ConstraintKind::EqualOrOptional:
15069+
return simplifyEqualOrOptionalConstraint(
15070+
constraint.getFirstType(), constraint.getSecondType(),
15071+
/*flags*/ None, constraint.getLocator());
15072+
1500715073
case ConstraintKind::ValueMember:
1500815074
case ConstraintKind::UnresolvedValueMember:
1500915075
return simplifyMemberConstraint(constraint.getKind(),

lib/Sema/CSSyntacticElement.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,8 @@ class SyntacticElementConstraintGenerator
616616
return;
617617
}
618618

619-
// Convert the contextual type to the pattern, which establishes the
620-
// bindings.
619+
// Require a conversion from the contextual type to the pattern type, which
620+
// establishes the bindings.
621621
cs.addConstraint(ConstraintKind::Conversion, context.getType(), patternType,
622622
locator);
623623

lib/Sema/Constraint.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
7474
case ConstraintKind::EscapableFunctionOf:
7575
case ConstraintKind::OpenedExistentialOf:
7676
case ConstraintKind::OptionalObject:
77+
case ConstraintKind::EqualOrOptional:
7778
case ConstraintKind::OneWayEqual:
7879
case ConstraintKind::OneWayBindParam:
7980
case ConstraintKind::UnresolvedMemberChainBase:
@@ -152,6 +153,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
152153
case ConstraintKind::EscapableFunctionOf:
153154
case ConstraintKind::OpenedExistentialOf:
154155
case ConstraintKind::OptionalObject:
156+
case ConstraintKind::EqualOrOptional:
155157
case ConstraintKind::ApplicableFunction:
156158
case ConstraintKind::DynamicCallableApplicableFunction:
157159
case ConstraintKind::ValueMember:
@@ -309,6 +311,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
309311
case ConstraintKind::SelfObjectOfProtocol:
310312
case ConstraintKind::DynamicCallableApplicableFunction:
311313
case ConstraintKind::OptionalObject:
314+
case ConstraintKind::EqualOrOptional:
312315
case ConstraintKind::Defaultable:
313316
case ConstraintKind::OneWayEqual:
314317
case ConstraintKind::OneWayBindParam:
@@ -493,6 +496,9 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm,
493496
break;
494497
case ConstraintKind::OptionalObject:
495498
Out << " optional with object type "; break;
499+
case ConstraintKind::EqualOrOptional:
500+
Out << " equal to or optional of ";
501+
break;
496502
case ConstraintKind::BindOverload: {
497503
Out << " bound to ";
498504
auto overload = getOverloadChoice();
@@ -727,6 +733,7 @@ gatherReferencedTypeVars(Constraint *constraint,
727733
case ConstraintKind::EscapableFunctionOf:
728734
case ConstraintKind::OpenedExistentialOf:
729735
case ConstraintKind::OptionalObject:
736+
case ConstraintKind::EqualOrOptional:
730737
case ConstraintKind::Defaultable:
731738
case ConstraintKind::SubclassOf:
732739
case ConstraintKind::ConformsTo:

0 commit comments

Comments
 (0)