Skip to content

Commit 237338b

Browse files
authored
Merge pull request #40224 from hamishknight/super-tuple-shuffle
2 parents d104e12 + 4aaec65 commit 237338b

File tree

14 files changed

+274
-2
lines changed

14 files changed

+274
-2
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,10 @@ WARNING(coercion_may_fail_warning,none,
11911191
"coercion from %0 to %1 may fail; use 'as?' or 'as!' instead",
11921192
(Type, Type))
11931193

1194+
WARNING(tuple_label_mismatch_warning,none,
1195+
"tuple conversion from %0 to %1 mismatches labels",
1196+
(Type, Type))
1197+
11941198
ERROR(missing_explicit_conversion,none,
11951199
"%0 is not implicitly convertible to %1; "
11961200
"did you mean to use 'as' to explicitly convert?", (Type, Type))

include/swift/Sema/CSFix.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@ enum class FixKind : uint8_t {
376376
/// Ignore a type mismatch between deduced element type and externally
377377
/// imposed one.
378378
IgnoreCollectionElementContextualMismatch,
379+
380+
/// Produce a warning for a tuple label mismatch.
381+
AllowTupleLabelMismatch,
379382
};
380383

381384
class ConstraintFix {
@@ -2802,6 +2805,27 @@ class AllowInvalidStaticMemberRefOnProtocolMetatype final
28022805
}
28032806
};
28042807

2808+
/// Emit a warning for mismatched tuple labels.
2809+
class AllowTupleLabelMismatch final : public ContextualMismatch {
2810+
AllowTupleLabelMismatch(ConstraintSystem &cs, Type fromType, Type toType,
2811+
ConstraintLocator *locator)
2812+
: ContextualMismatch(cs, FixKind::AllowTupleLabelMismatch, fromType,
2813+
toType, locator, /*warning*/ true) {}
2814+
2815+
public:
2816+
std::string getName() const override { return "allow tuple label mismatch"; }
2817+
2818+
bool diagnose(const Solution &solution, bool asNote = false) const override;
2819+
2820+
static AllowTupleLabelMismatch *create(ConstraintSystem &cs, Type fromType,
2821+
Type toType,
2822+
ConstraintLocator *locator);
2823+
2824+
static bool classof(const ConstraintFix *fix) {
2825+
return fix->getKind() == FixKind::AllowTupleLabelMismatch;
2826+
}
2827+
};
2828+
28052829
class AllowNonOptionalWeak final : public ConstraintFix {
28062830
AllowNonOptionalWeak(ConstraintSystem &cs, ConstraintLocator *locator)
28072831
: ConstraintFix(cs, FixKind::AllowNonOptionalWeak, locator) {}

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.
@@ -689,6 +695,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
689695
case ConstraintKind::KeyPath:
690696
case ConstraintKind::KeyPathApplication:
691697
case ConstraintKind::Defaultable:
698+
case ConstraintKind::BindTupleOfFunctionParams:
692699
return ConstraintClassification::TypeProperty;
693700

694701
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
@@ -1387,6 +1387,7 @@ void PotentialBindings::infer(Constraint *constraint) {
13871387
case ConstraintKind::KeyPath:
13881388
case ConstraintKind::ClosureBodyElement:
13891389
case ConstraintKind::Conjunction:
1390+
case ConstraintKind::BindTupleOfFunctionParams:
13901391
// Constraints from which we can't do anything.
13911392
break;
13921393

lib/Sema/CSDiagnostics.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7869,6 +7869,12 @@ bool InvalidWeakAttributeUse::diagnoseAsError() {
78697869
return true;
78707870
}
78717871

7872+
bool TupleLabelMismatchWarning::diagnoseAsError() {
7873+
emitDiagnostic(diag::tuple_label_mismatch_warning, getFromType(), getToType())
7874+
.highlight(getSourceRange());
7875+
return true;
7876+
}
7877+
78727878
bool SwiftToCPointerConversionInInvalidContext::diagnoseAsError() {
78737879
auto argInfo = getFunctionArgApplyInfo(getLocator());
78747880
if (!argInfo)

lib/Sema/CSDiagnostics.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2620,6 +2620,16 @@ class InvalidWeakAttributeUse final : public FailureDiagnostic {
26202620
bool diagnoseAsError() override;
26212621
};
26222622

2623+
/// Emit a warning for mismatched tuple labels.
2624+
class TupleLabelMismatchWarning final : public ContextualFailure {
2625+
public:
2626+
TupleLabelMismatchWarning(const Solution &solution, Type fromType,
2627+
Type toType, ConstraintLocator *locator)
2628+
: ContextualFailure(solution, fromType, toType, locator) {}
2629+
2630+
bool diagnoseAsError() override;
2631+
};
2632+
26232633
/// Diagnose situations where Swift -> C pointer implicit conversion
26242634
/// is attempted on a Swift function instead of one imported from C header.
26252635
///

lib/Sema/CSFix.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,6 +2024,20 @@ AllowNonOptionalWeak *AllowNonOptionalWeak::create(ConstraintSystem &cs,
20242024
return new (cs.getAllocator()) AllowNonOptionalWeak(cs, locator);
20252025
}
20262026

2027+
AllowTupleLabelMismatch *
2028+
AllowTupleLabelMismatch::create(ConstraintSystem &cs, Type fromType,
2029+
Type toType, ConstraintLocator *locator) {
2030+
return new (cs.getAllocator())
2031+
AllowTupleLabelMismatch(cs, fromType, toType, locator);
2032+
}
2033+
2034+
bool AllowTupleLabelMismatch::diagnose(const Solution &solution,
2035+
bool asNote) const {
2036+
TupleLabelMismatchWarning warning(solution, getFromType(), getToType(),
2037+
getLocator());
2038+
return warning.diagnose(asNote);
2039+
}
2040+
20272041
bool AllowSwiftToCPointerConversion::diagnose(const Solution &solution,
20282042
bool asNote) const {
20292043
SwiftToCPointerConversionInInvalidContext failure(solution, getLocator());

lib/Sema/CSGen.cpp

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

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

lib/Sema/CSSimplify.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,6 +1620,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
16201620
}
16211621
}
16221622

1623+
auto hasLabelMismatch = false;
16231624
for (unsigned i = 0, n = tuple1->getNumElements(); i != n; ++i) {
16241625
const auto &elt1 = tuple1->getElement(i);
16251626
const auto &elt2 = tuple2->getElement(i);
@@ -1641,6 +1642,11 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
16411642
// used at some other position.
16421643
if (elt2.hasName() && tuple1->getNamedElementId(elt2.getName()) != -1)
16431644
return getTypeMatchFailure(locator);
1645+
1646+
// If both elements have names and they mismatch, make a note of it
1647+
// so we can emit a warning.
1648+
if (elt1.hasName() && elt2.hasName())
1649+
hasLabelMismatch = true;
16441650
}
16451651
}
16461652

@@ -1656,6 +1662,13 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
16561662
return result;
16571663
}
16581664

1665+
if (hasLabelMismatch) {
1666+
// If we had a label mismatch, emit a warning. This is something we
1667+
// shouldn't permit, as it's more permissive than what a conversion would
1668+
// allow. Ideally we'd turn this into an error in Swift 6 mode.
1669+
recordFix(AllowTupleLabelMismatch::create(
1670+
*this, tuple1, tuple2, getConstraintLocator(locator)));
1671+
}
16591672
return getTypeMatchSuccess();
16601673
}
16611674

@@ -1700,6 +1713,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
17001713
case ConstraintKind::UnresolvedMemberChainBase:
17011714
case ConstraintKind::PropertyWrapper:
17021715
case ConstraintKind::ClosureBodyElement:
1716+
case ConstraintKind::BindTupleOfFunctionParams:
17031717
llvm_unreachable("Not a conversion");
17041718
}
17051719

@@ -1839,6 +1853,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
18391853
case ConstraintKind::UnresolvedMemberChainBase:
18401854
case ConstraintKind::PropertyWrapper:
18411855
case ConstraintKind::ClosureBodyElement:
1856+
case ConstraintKind::BindTupleOfFunctionParams:
18421857
return true;
18431858
}
18441859

@@ -2250,6 +2265,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
22502265
case ConstraintKind::UnresolvedMemberChainBase:
22512266
case ConstraintKind::PropertyWrapper:
22522267
case ConstraintKind::ClosureBodyElement:
2268+
case ConstraintKind::BindTupleOfFunctionParams:
22532269
llvm_unreachable("Not a relational constraint");
22542270
}
22552271

@@ -5337,6 +5353,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
53375353
case ConstraintKind::UnresolvedMemberChainBase:
53385354
case ConstraintKind::PropertyWrapper:
53395355
case ConstraintKind::ClosureBodyElement:
5356+
case ConstraintKind::BindTupleOfFunctionParams:
53405357
llvm_unreachable("Not a relational constraint");
53415358
}
53425359
}
@@ -6310,6 +6327,19 @@ ConstraintSystem::simplifyConstructionConstraint(
63106327
fnLocator,
63116328
ConstraintLocator::ConstructorMember));
63126329

6330+
// HACK: Bind the function's parameter list as a tuple to a type variable.
6331+
// This only exists to preserve compatibility with rdar://85263844, as it can
6332+
// affect the prioritization of bindings, which can affect behavior for tuple
6333+
// matching as tuple subtyping is currently a *weaker* constraint than tuple
6334+
// conversion.
6335+
if (!getASTContext().isSwiftVersionAtLeast(6)) {
6336+
auto paramTypeVar = createTypeVariable(
6337+
getConstraintLocator(locator, ConstraintLocator::ApplyArgument),
6338+
TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape);
6339+
addConstraint(ConstraintKind::BindTupleOfFunctionParams, memberType,
6340+
paramTypeVar, locator);
6341+
}
6342+
63136343
addConstraint(ConstraintKind::ApplicableFunction, fnType, memberType,
63146344
fnLocator);
63156345

@@ -7133,6 +7163,59 @@ ConstraintSystem::simplifyOptionalObjectConstraint(
71337163
return SolutionKind::Solved;
71347164
}
71357165

7166+
ConstraintSystem::SolutionKind
7167+
ConstraintSystem::simplifyBindTupleOfFunctionParamsConstraint(
7168+
Type first, Type second, TypeMatchOptions flags,
7169+
ConstraintLocatorBuilder locator) {
7170+
auto simplified = simplifyType(first);
7171+
auto simplifiedCopy = simplified;
7172+
7173+
unsigned unwrapCount = 0;
7174+
if (shouldAttemptFixes()) {
7175+
while (auto objectTy = simplified->getOptionalObjectType()) {
7176+
simplified = objectTy;
7177+
7178+
// Track how many times we do this so that we can record a fix for each.
7179+
++unwrapCount;
7180+
}
7181+
7182+
if (simplified->isPlaceholder()) {
7183+
if (auto *typeVar = second->getAs<TypeVariableType>())
7184+
recordPotentialHole(typeVar);
7185+
return SolutionKind::Solved;
7186+
}
7187+
}
7188+
7189+
if (simplified->isTypeVariableOrMember()) {
7190+
if (!flags.contains(TMF_GenerateConstraints))
7191+
return SolutionKind::Unsolved;
7192+
7193+
addUnsolvedConstraint(
7194+
Constraint::create(*this, ConstraintKind::BindTupleOfFunctionParams,
7195+
simplified, second, getConstraintLocator(locator)));
7196+
return SolutionKind::Solved;
7197+
}
7198+
7199+
auto *funcTy = simplified->getAs<FunctionType>();
7200+
if (!funcTy)
7201+
return SolutionKind::Error;
7202+
7203+
auto tupleTy =
7204+
AnyFunctionType::composeTuple(getASTContext(), funcTy->getParams(),
7205+
/*wantParamFlags*/ false);
7206+
7207+
addConstraint(ConstraintKind::Bind, tupleTy, second,
7208+
locator.withPathElement(ConstraintLocator::FunctionArgument));
7209+
7210+
if (unwrapCount > 0) {
7211+
auto *fix = ForceOptional::create(*this, simplifiedCopy, second,
7212+
getConstraintLocator(locator));
7213+
if (recordFix(fix, /*impact=*/unwrapCount))
7214+
return SolutionKind::Error;
7215+
}
7216+
return SolutionKind::Solved;
7217+
}
7218+
71367219
static bool isForKeyPathSubscript(ConstraintSystem &cs,
71377220
ConstraintLocator *locator) {
71387221
if (!locator || !locator->getAnchor())
@@ -11963,6 +12046,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1196312046
case FixKind::DropThrowsAttribute:
1196412047
case FixKind::DropAsyncAttribute:
1196512048
case FixKind::AllowSwiftToCPointerConversion:
12049+
case FixKind::AllowTupleLabelMismatch:
1196612050
llvm_unreachable("handled elsewhere");
1196712051
}
1196812052

@@ -12048,6 +12132,10 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
1204812132
return simplifyUnresolvedMemberChainBaseConstraint(first, second, subflags,
1204912133
locator);
1205012134

12135+
case ConstraintKind::BindTupleOfFunctionParams:
12136+
return simplifyBindTupleOfFunctionParamsConstraint(first, second, subflags,
12137+
locator);
12138+
1205112139
case ConstraintKind::ValueMember:
1205212140
case ConstraintKind::UnresolvedValueMember:
1205312141
case ConstraintKind::ValueWitness:
@@ -12591,6 +12679,11 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1259112679
constraint.getClosureElement(), constraint.getElementContext(),
1259212680
constraint.isDiscardedElement(),
1259312681
/*flags=*/None, constraint.getLocator());
12682+
12683+
case ConstraintKind::BindTupleOfFunctionParams:
12684+
return simplifyBindTupleOfFunctionParamsConstraint(
12685+
constraint.getFirstType(), constraint.getSecondType(), /*flags*/ None,
12686+
constraint.getLocator());
1259412687
}
1259512688

1259612689
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:
@@ -304,6 +306,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
304306
case ConstraintKind::DefaultClosureType:
305307
case ConstraintKind::UnresolvedMemberChainBase:
306308
case ConstraintKind::PropertyWrapper:
309+
case ConstraintKind::BindTupleOfFunctionParams:
307310
return create(cs, getKind(), getFirstType(), getSecondType(), getLocator());
308311

309312
case ConstraintKind::ApplicableFunction:
@@ -505,6 +508,10 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
505508
Out << " can default to ";
506509
break;
507510

511+
case ConstraintKind::BindTupleOfFunctionParams:
512+
Out << " bind tuple of function params to ";
513+
break;
514+
508515
case ConstraintKind::Disjunction:
509516
llvm_unreachable("disjunction handled above");
510517
case ConstraintKind::Conjunction:
@@ -665,6 +672,7 @@ gatherReferencedTypeVars(Constraint *constraint,
665672
case ConstraintKind::DefaultClosureType:
666673
case ConstraintKind::UnresolvedMemberChainBase:
667674
case ConstraintKind::PropertyWrapper:
675+
case ConstraintKind::BindTupleOfFunctionParams:
668676
constraint->getFirstType()->getTypeVariables(typeVars);
669677
constraint->getSecondType()->getTypeVariables(typeVars);
670678
break;

0 commit comments

Comments
 (0)