Skip to content

Commit da36a2c

Browse files
committed
[CS] Restore a type variable for compatibility with rdar://85263844
Despite being otherwise disconnected from the constraint system, it's possible for it to affect how we type-check tuple matches in certain cases. This is due to the fact that: - It can have a lower type variable ID than an opened generic parameter type, so becomes the representative when merged with it. And because it has a different locator, this can influence binding prioritization. - Tuple subtyping is broken, as it's currently a *weaker* relationship than conversion. Therefore, temporarily restore this bit of logic for language versions < 6. If possible, we should try and fix tuple subtying in Swift 6 mode to not accept label mismatches, so that it's not more permissive than tuple conversion. rdar://85263844
1 parent 0ae1203 commit da36a2c

File tree

8 files changed

+171
-2
lines changed

8 files changed

+171
-2
lines changed

include/swift/Sema/Constraint.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,12 @@ enum class ConstraintKind : char {
213213
/// one type - type variable representing type of a node, other side is
214214
/// the AST node to infer the type for.
215215
ClosureBodyElement,
216+
/// Do not add new uses of this, it only exists to retain compatibility for
217+
/// rdar://85263844.
218+
///
219+
/// Binds the RHS type to a tuple of the params of a function typed LHS. Note
220+
/// this discards function parameter flags.
221+
BindTupleOfFunctionParams
216222
};
217223

218224
/// Classification of the different kinds of constraints.
@@ -685,6 +691,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
685691
case ConstraintKind::KeyPath:
686692
case ConstraintKind::KeyPathApplication:
687693
case ConstraintKind::Defaultable:
694+
case ConstraintKind::BindTupleOfFunctionParams:
688695
return ConstraintClassification::TypeProperty;
689696

690697
case ConstraintKind::Disjunction:

include/swift/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4748,6 +4748,12 @@ class ConstraintSystem {
47484748
TypeMatchOptions flags,
47494749
ConstraintLocatorBuilder locator);
47504750

4751+
/// Attempt to simplify a BindTupleOfFunctionParams constraint.
4752+
SolutionKind
4753+
simplifyBindTupleOfFunctionParamsConstraint(Type first, Type second,
4754+
TypeMatchOptions flags,
4755+
ConstraintLocatorBuilder locator);
4756+
47514757
/// Attempt to simplify the ApplicableFunction constraint.
47524758
SolutionKind simplifyApplicableFnConstraint(
47534759
Type type1, Type type2,

lib/Sema/CSBindings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,7 @@ void PotentialBindings::infer(Constraint *constraint) {
13781378
case ConstraintKind::KeyPath:
13791379
case ConstraintKind::ClosureBodyElement:
13801380
case ConstraintKind::Conjunction:
1381+
case ConstraintKind::BindTupleOfFunctionParams:
13811382
// Constraints from which we can't do anything.
13821383
break;
13831384

lib/Sema/CSGen.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,19 @@ namespace {
15251525
auto methodTy =
15261526
CS.createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape);
15271527

1528+
// HACK: Bind the function's parameter list as a tuple to a type
1529+
// variable. This only exists to preserve compatibility with
1530+
// rdar://85263844, as it can affect the prioritization of bindings,
1531+
// which can affect behavior for tuple matching as tuple subtyping is
1532+
// currently a *weaker* constraint than tuple conversion.
1533+
if (!CS.getASTContext().isSwiftVersionAtLeast(6)) {
1534+
auto paramTypeVar = CS.createTypeVariable(
1535+
CS.getConstraintLocator(expr, ConstraintLocator::ApplyArgument),
1536+
TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape);
1537+
CS.addConstraint(ConstraintKind::BindTupleOfFunctionParams, methodTy,
1538+
paramTypeVar, CS.getConstraintLocator(expr));
1539+
}
1540+
15281541
CS.addValueMemberConstraint(
15291542
baseTy, expr->getName(), methodTy, CurDC,
15301543
expr->getFunctionRefKind(),

lib/Sema/CSSimplify.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
17001700
case ConstraintKind::UnresolvedMemberChainBase:
17011701
case ConstraintKind::PropertyWrapper:
17021702
case ConstraintKind::ClosureBodyElement:
1703+
case ConstraintKind::BindTupleOfFunctionParams:
17031704
llvm_unreachable("Not a conversion");
17041705
}
17051706

@@ -1839,6 +1840,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
18391840
case ConstraintKind::UnresolvedMemberChainBase:
18401841
case ConstraintKind::PropertyWrapper:
18411842
case ConstraintKind::ClosureBodyElement:
1843+
case ConstraintKind::BindTupleOfFunctionParams:
18421844
return true;
18431845
}
18441846

@@ -2250,6 +2252,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
22502252
case ConstraintKind::UnresolvedMemberChainBase:
22512253
case ConstraintKind::PropertyWrapper:
22522254
case ConstraintKind::ClosureBodyElement:
2255+
case ConstraintKind::BindTupleOfFunctionParams:
22532256
llvm_unreachable("Not a relational constraint");
22542257
}
22552258

@@ -5337,6 +5340,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
53375340
case ConstraintKind::UnresolvedMemberChainBase:
53385341
case ConstraintKind::PropertyWrapper:
53395342
case ConstraintKind::ClosureBodyElement:
5343+
case ConstraintKind::BindTupleOfFunctionParams:
53405344
llvm_unreachable("Not a relational constraint");
53415345
}
53425346
}
@@ -6308,6 +6312,19 @@ ConstraintSystem::simplifyConstructionConstraint(
63086312
fnLocator,
63096313
ConstraintLocator::ConstructorMember));
63106314

6315+
// HACK: Bind the function's parameter list as a tuple to a type variable.
6316+
// This only exists to preserve compatibility with rdar://85263844, as it can
6317+
// affect the prioritization of bindings, which can affect behavior for tuple
6318+
// matching as tuple subtyping is currently a *weaker* constraint than tuple
6319+
// conversion.
6320+
if (!getASTContext().isSwiftVersionAtLeast(6)) {
6321+
auto paramTypeVar = createTypeVariable(
6322+
getConstraintLocator(locator, ConstraintLocator::ApplyArgument),
6323+
TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape);
6324+
addConstraint(ConstraintKind::BindTupleOfFunctionParams, memberType,
6325+
paramTypeVar, locator);
6326+
}
6327+
63116328
addConstraint(ConstraintKind::ApplicableFunction, fnType, memberType,
63126329
fnLocator);
63136330

@@ -7131,6 +7148,59 @@ ConstraintSystem::simplifyOptionalObjectConstraint(
71317148
return SolutionKind::Solved;
71327149
}
71337150

7151+
ConstraintSystem::SolutionKind
7152+
ConstraintSystem::simplifyBindTupleOfFunctionParamsConstraint(
7153+
Type first, Type second, TypeMatchOptions flags,
7154+
ConstraintLocatorBuilder locator) {
7155+
auto simplified = simplifyType(first);
7156+
auto simplifiedCopy = simplified;
7157+
7158+
unsigned unwrapCount = 0;
7159+
if (shouldAttemptFixes()) {
7160+
while (auto objectTy = simplified->getOptionalObjectType()) {
7161+
simplified = objectTy;
7162+
7163+
// Track how many times we do this so that we can record a fix for each.
7164+
++unwrapCount;
7165+
}
7166+
7167+
if (simplified->isPlaceholder()) {
7168+
if (auto *typeVar = second->getAs<TypeVariableType>())
7169+
recordPotentialHole(typeVar);
7170+
return SolutionKind::Solved;
7171+
}
7172+
}
7173+
7174+
if (simplified->isTypeVariableOrMember()) {
7175+
if (!flags.contains(TMF_GenerateConstraints))
7176+
return SolutionKind::Unsolved;
7177+
7178+
addUnsolvedConstraint(
7179+
Constraint::create(*this, ConstraintKind::BindTupleOfFunctionParams,
7180+
simplified, second, getConstraintLocator(locator)));
7181+
return SolutionKind::Solved;
7182+
}
7183+
7184+
auto *funcTy = simplified->getAs<FunctionType>();
7185+
if (!funcTy)
7186+
return SolutionKind::Error;
7187+
7188+
auto tupleTy =
7189+
AnyFunctionType::composeTuple(getASTContext(), funcTy->getParams(),
7190+
/*wantParamFlags*/ false);
7191+
7192+
addConstraint(ConstraintKind::Bind, tupleTy, second,
7193+
locator.withPathElement(ConstraintLocator::FunctionArgument));
7194+
7195+
if (unwrapCount > 0) {
7196+
auto *fix = ForceOptional::create(*this, simplifiedCopy, second,
7197+
getConstraintLocator(locator));
7198+
if (recordFix(fix, /*impact=*/unwrapCount))
7199+
return SolutionKind::Error;
7200+
}
7201+
return SolutionKind::Solved;
7202+
}
7203+
71347204
static bool isForKeyPathSubscript(ConstraintSystem &cs,
71357205
ConstraintLocator *locator) {
71367206
if (!locator || !locator->getAnchor())
@@ -12046,6 +12116,10 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
1204612116
return simplifyUnresolvedMemberChainBaseConstraint(first, second, subflags,
1204712117
locator);
1204812118

12119+
case ConstraintKind::BindTupleOfFunctionParams:
12120+
return simplifyBindTupleOfFunctionParamsConstraint(first, second, subflags,
12121+
locator);
12122+
1204912123
case ConstraintKind::ValueMember:
1205012124
case ConstraintKind::UnresolvedValueMember:
1205112125
case ConstraintKind::ValueWitness:
@@ -12588,6 +12662,11 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1258812662
return simplifyClosureBodyElementConstraint(
1258912663
constraint.getClosureElement(), constraint.getElementContext(),
1259012664
/*flags=*/None, constraint.getLocator());
12665+
12666+
case ConstraintKind::BindTupleOfFunctionParams:
12667+
return simplifyBindTupleOfFunctionParamsConstraint(
12668+
constraint.getFirstType(), constraint.getSecondType(), /*flags*/ None,
12669+
constraint.getLocator());
1259112670
}
1259212671

1259312672
llvm_unreachable("Unhandled ConstraintKind in switch.");

lib/Sema/Constraint.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
7777
case ConstraintKind::OneWayBindParam:
7878
case ConstraintKind::UnresolvedMemberChainBase:
7979
case ConstraintKind::PropertyWrapper:
80+
case ConstraintKind::BindTupleOfFunctionParams:
8081
assert(!First.isNull());
8182
assert(!Second.isNull());
8283
break;
@@ -161,6 +162,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
161162
case ConstraintKind::UnresolvedMemberChainBase:
162163
case ConstraintKind::PropertyWrapper:
163164
case ConstraintKind::ClosureBodyElement:
165+
case ConstraintKind::BindTupleOfFunctionParams:
164166
llvm_unreachable("Wrong constructor");
165167

166168
case ConstraintKind::KeyPath:
@@ -303,6 +305,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
303305
case ConstraintKind::DefaultClosureType:
304306
case ConstraintKind::UnresolvedMemberChainBase:
305307
case ConstraintKind::PropertyWrapper:
308+
case ConstraintKind::BindTupleOfFunctionParams:
306309
return create(cs, getKind(), getFirstType(), getSecondType(), getLocator());
307310

308311
case ConstraintKind::ApplicableFunction:
@@ -503,6 +506,10 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
503506
Out << " can default to ";
504507
break;
505508

509+
case ConstraintKind::BindTupleOfFunctionParams:
510+
Out << " bind tuple of function params to ";
511+
break;
512+
506513
case ConstraintKind::Disjunction:
507514
llvm_unreachable("disjunction handled above");
508515
case ConstraintKind::Conjunction:
@@ -663,6 +670,7 @@ gatherReferencedTypeVars(Constraint *constraint,
663670
case ConstraintKind::DefaultClosureType:
664671
case ConstraintKind::UnresolvedMemberChainBase:
665672
case ConstraintKind::PropertyWrapper:
673+
case ConstraintKind::BindTupleOfFunctionParams:
666674
constraint->getFirstType()->getTypeVariables(typeVars);
667675
constraint->getSecondType()->getTypeVariables(typeVars);
668676
break;

test/Constraints/construction.swift

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,26 @@ func test_that_optionality_of_closure_result_is_preserved() {
267267

268268
// rdar://85263844 - initializer 'init(_:)' requires the types be equivalent
269269
func rdar85263844(arr: [(q: String, a: Int)]) -> AnySequence<(question: String, answer: Int)> {
270-
AnySequence(arr.map { $0 }) // FIXME: This is supposed to type-check.
271-
// expected-error@-1 {{initializer 'init(_:)' requires the types '(question: String, answer: Int)' and '(q: String, a: Int)' be equivalent}}
270+
AnySequence(arr.map { $0 })
271+
}
272+
273+
// Another case for rdar://85263844
274+
protocol P {
275+
associatedtype Element
276+
}
277+
extension Array : P {}
278+
279+
public struct S4<T> {
280+
init<S : P>(_ x: S) where S.Element == T {}
281+
init(_ x: Int) {}
282+
}
283+
284+
extension S4 where T == (outer: Int, y: Int) {
285+
init(arr: [Int]) {
286+
self.init(arr.map { (inner: $0, y: $0) })
287+
}
288+
}
289+
290+
public func rdar85263844_2(_ x: [Int]) -> S4<(outer: Int, y: Int)> {
291+
S4(x.map { (inner: $0, y: $0) })
272292
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 6
2+
3+
// '-swift-version 6' is currently asserts-only
4+
// REQUIRES: asserts
5+
6+
// rdar://85263844 - initializer 'init(_:)' requires the types be equivalent
7+
func rdar85263844(arr: [(q: String, a: Int)]) -> AnySequence<(question: String, answer: Int)> {
8+
AnySequence(arr.map { $0 })
9+
// expected-error@-1 {{initializer 'init(_:)' requires the types '(question: String, answer: Int)' and '(q: String, a: Int)' be equivalent}}
10+
}
11+
12+
// Another case for rdar://85263844
13+
protocol P {
14+
associatedtype Element
15+
}
16+
extension Array : P {}
17+
18+
public struct S4<T> {
19+
init<S : P>(_ x: S) where S.Element == T {}
20+
init(_ x: Int) {}
21+
}
22+
23+
extension S4 where T == (outer: Int, y: Int) {
24+
init(arr: [Int]) {
25+
// FIXME: This ideally shouldn't compile either, but because of the way we
26+
// generate constraints for it, it continues to compile. We should fix
27+
// tuple subtyping for Swift 6 mode to not accept label mismatches.
28+
self.init(arr.map { (inner: $0, y: $0) })
29+
}
30+
}
31+
32+
public func rdar85263844_2(_ x: [Int]) -> S4<(outer: Int, y: Int)> {
33+
// FIXME: Bad error message.
34+
S4(x.map { (inner: $0, y: $0) }) // expected-error {{type of expression is ambiguous without more context}}
35+
}

0 commit comments

Comments
 (0)