Skip to content

[5.9][ConstraintSystem] Anthology of changes to variadic generics #65586

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8a9afc8
[Diagnostics] Suppress unused expression warning if result is discard…
xedin Apr 26, 2023
341395f
[ConstraintSystem] Add a new locator element to identify pack expansi…
xedin Apr 6, 2023
19b8edb
[CSSolver] Add recorded pack expansion environments to solutions
xedin Apr 12, 2023
73d189a
[AST] PackMatching: Make pack expansion type check pluggable
xedin Apr 6, 2023
69b37ca
[ConstraintSystem] Introduce `TVO_PackExpansion`
xedin Apr 6, 2023
9501315
[ConstraintSystem] Implement pack expansion type opening
xedin Apr 6, 2023
ee0d603
[ConstraintSystem] TypeSimplifier: Prevent flattening of partially re…
xedin Apr 7, 2023
73fa561
[ConstraintSystem] Handle presence of pack expansion type variables w…
xedin Apr 10, 2023
a8598bf
[ConstraintSystem] Implement pack expansion variable resolution
xedin Apr 11, 2023
54bd9eb
[CSSimplify] Prevent merging of type expansion type variables
xedin Apr 11, 2023
9bf21de
[CSSimplify] Handle presence of pack expansion if tuples and shape co…
xedin Apr 11, 2023
737dc19
[CSSimplify] Delay `.element` lookup if pack expansion is not yet res…
xedin Apr 11, 2023
f17f5b4
[CSSimplify] Introduce `containsPackExpansionType` that handles pack …
xedin Apr 12, 2023
dda8910
[AST] `containsPackExpansion` should not be used when type variables …
xedin Apr 12, 2023
e6d434a
[CSSimplify] Delay matching if one of the types is a tuple with unres…
xedin Apr 12, 2023
f7dadd9
[CSBindings] Mark type variables that represent packs as involving ty…
xedin Apr 12, 2023
3cc2008
[ConstraintSystem] TypeSimplifier: If pattern and shape are packs - p…
xedin Apr 12, 2023
ffb9762
[ConstraintSystem] TypeSimplifier: Unwrap tuple if pack expansion var…
xedin Apr 12, 2023
4db3566
[ConstraintSystem] Form a special one type binding set for pack expan…
xedin Apr 12, 2023
8903d2b
[ConstraintSystem] Adjust `openType` and `openUnboundGenericType` to …
xedin Apr 12, 2023
ac7cf68
[CSSimplify] Type matching should maintain tuples when matching types…
xedin Apr 13, 2023
1c35ae0
[ConstraintSystem] Record opened pack expansion type in the locator e…
xedin Apr 13, 2023
9d80c4e
[ConstraintSystem] Add a locator to `openType` and some of its callers
xedin Apr 14, 2023
1d47621
[CSSimplify] Merge binding inference logic with `PackElementOf` const…
xedin Apr 18, 2023
2ae78d6
[CSDiagnostics] Teach generic parameter restoration logic about pack …
xedin Apr 20, 2023
b1e55cb
[CSSimplify] Prevent contextual mismatch diagnostics from seeing one-…
xedin Apr 20, 2023
fe07084
[CSSimplify] Adjust `replaceTypeVariablesWithFreshPacks` to propagate…
xedin Apr 21, 2023
22d8e1a
[CSSimplify] Propagate contextual types to pack expansion variables
xedin Apr 24, 2023
306a857
[ConstraintSystem] Add `same-shape` constraint
xedin Apr 24, 2023
4e9e861
[CSSimplify] Add tailored diagnostics for same-shape mismatches relat…
xedin Apr 25, 2023
faa19f0
[CSDiagnostics] Unwrap some packs types for diagnostics
xedin Apr 25, 2023
7a6977c
[CSFix] Add a skeleton of a fix for argument destructuring to match p…
xedin Apr 25, 2023
e5ed5f0
[CSDiagnostics] Diagnose situations when value pack expansion does ex…
xedin Apr 25, 2023
998ae86
[CSSimplify] Detect and diagnose passing a tuple to pack expansion th…
xedin Apr 25, 2023
9597f54
[CSSimplify] If pack type has holes - its shape is a hole
xedin Apr 26, 2023
4df6ce2
[CSFix] Add a fix to allow value pack expansions without pack references
xedin Apr 27, 2023
f45654b
[CSDiagnostics] Add a diagnostic for pack expansions without pack ref…
xedin Apr 27, 2023
f457a7e
[CSGen] Detect and diagnose invalid pack expansion expressions
xedin Apr 27, 2023
a3d67ba
[CSSimplify] Fix attempt to rebind type variables in sequence element…
xedin Apr 21, 2023
e112172
[CSGen] Allow `is` pattern types to be holes
xedin Apr 21, 2023
a767620
[ConstraintSystem] NFC: Standardize the way of type holefication
xedin Apr 21, 2023
47ac416
[CSGen] Allow expression pattern types to be holes
xedin Apr 24, 2023
554f2a4
[CSSimplify] Prevent invalid pack references from causing infinite loops
xedin Apr 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -5415,6 +5415,15 @@ ERROR(tuple_duplicate_label,none,
"cannot create a tuple with a duplicate element label", ())
ERROR(multiple_ellipsis_in_tuple,none,
"only a single element can be variadic", ())
ERROR(cannot_convert_tuple_into_pack_expansion_parameter,none,
"value pack expansion at parameter #%0 expects %1 separate arguments"
"%select{|; remove extra parentheses to change tuple into separate arguments}2",
(unsigned, unsigned, bool))
NOTE(cannot_convert_tuple_into_pack_expansion_parameter_note,none,
"value pack expansion at parameter #%0 expects %1 separate arguments",
(unsigned, unsigned))
ERROR(value_expansion_not_variadic,none,
"value pack expansion must contain at least one pack reference", ())

ERROR(expansion_not_same_shape,none,
"pack expansion %0 requires that %1 and %2 have the same shape",
Expand Down
58 changes: 33 additions & 25 deletions include/swift/AST/PackExpansionMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,13 @@ class TypeListPackMatcher {
ArrayRef<Element> lhsElements;
ArrayRef<Element> rhsElements;

std::function<bool(Type)> IsPackExpansionType;
protected:
TypeListPackMatcher(ASTContext &ctx, ArrayRef<Element> lhs,
ArrayRef<Element> rhs)
: ctx(ctx), lhsElements(lhs), rhsElements(rhs) {}
ArrayRef<Element> rhs,
std::function<bool(Type)> isPackExpansionType)
: ctx(ctx), lhsElements(lhs), rhsElements(rhs),
IsPackExpansionType(isPackExpansionType) {}

public:
SmallVector<MatchedPair, 4> pairs;
Expand Down Expand Up @@ -86,8 +89,8 @@ class TypeListPackMatcher {
auto lhsType = getElementType(lhsElt);
auto rhsType = getElementType(rhsElt);

if (lhsType->template is<PackExpansionType>() ||
rhsType->template is<PackExpansionType>()) {
if (IsPackExpansionType(lhsType) ||
IsPackExpansionType(rhsType)) {
break;
}

Expand Down Expand Up @@ -115,8 +118,8 @@ class TypeListPackMatcher {
auto lhsType = getElementType(lhsElt);
auto rhsType = getElementType(rhsElt);

if (lhsType->template is<PackExpansionType>() ||
rhsType->template is<PackExpansionType>()) {
if (IsPackExpansionType(lhsType) ||
IsPackExpansionType(rhsType)) {
break;
}

Expand All @@ -139,7 +142,7 @@ class TypeListPackMatcher {
// to what remains of the right hand side.
if (lhsElts.size() == 1) {
auto lhsType = getElementType(lhsElts[0]);
if (auto *lhsExpansion = lhsType->template getAs<PackExpansionType>()) {
if (IsPackExpansionType(lhsType)) {
unsigned lhsIdx = prefixLength;
unsigned rhsIdx = prefixLength;

Expand All @@ -154,7 +157,7 @@ class TypeListPackMatcher {
auto rhs = createPackBinding(rhsTypes);

// FIXME: Check lhs flags
pairs.emplace_back(lhsExpansion, rhs, lhsIdx, rhsIdx);
pairs.emplace_back(lhsType, rhs, lhsIdx, rhsIdx);
return false;
}
}
Expand All @@ -163,7 +166,7 @@ class TypeListPackMatcher {
// to what remains of the left hand side.
if (rhsElts.size() == 1) {
auto rhsType = getElementType(rhsElts[0]);
if (auto *rhsExpansion = rhsType->template getAs<PackExpansionType>()) {
if (IsPackExpansionType(rhsType)) {
unsigned lhsIdx = prefixLength;
unsigned rhsIdx = prefixLength;

Expand All @@ -178,7 +181,7 @@ class TypeListPackMatcher {
auto lhs = createPackBinding(lhsTypes);

// FIXME: Check rhs flags
pairs.emplace_back(lhs, rhsExpansion, lhsIdx, rhsIdx);
pairs.emplace_back(lhs, rhsType, lhsIdx, rhsIdx);
return false;
}
}
Expand All @@ -197,14 +200,11 @@ class TypeListPackMatcher {
Type getElementType(const Element &) const;
ParameterTypeFlags getElementFlags(const Element &) const;

PackExpansionType *createPackBinding(ArrayRef<Type> types) const {
Type createPackBinding(ArrayRef<Type> types) const {
// If there is only one element and it's a PackExpansionType,
// return it directly.
if (types.size() == 1) {
if (auto *expansionType = types.front()->getAs<PackExpansionType>()) {
return expansionType;
}
}
if (types.size() == 1 && IsPackExpansionType(types.front()))
return types.front();

// Otherwise, wrap the elements in PackExpansionType(PackType(...)).
auto *packType = PackType::get(ctx, types);
Expand All @@ -220,10 +220,12 @@ class TypeListPackMatcher {
/// other side.
class TuplePackMatcher : public TypeListPackMatcher<TupleTypeElt> {
public:
TuplePackMatcher(TupleType *lhsTuple, TupleType *rhsTuple)
: TypeListPackMatcher(lhsTuple->getASTContext(),
lhsTuple->getElements(),
rhsTuple->getElements()) {}
TuplePackMatcher(
TupleType *lhsTuple, TupleType *rhsTuple,
std::function<bool(Type)> isPackExpansionType =
[](Type T) { return T->is<PackExpansionType>(); })
: TypeListPackMatcher(lhsTuple->getASTContext(), lhsTuple->getElements(),
rhsTuple->getElements(), isPackExpansionType) {}
};

/// Performs a structural match of two lists of (unlabeled) function
Expand All @@ -235,9 +237,12 @@ class TuplePackMatcher : public TypeListPackMatcher<TupleTypeElt> {
/// other side.
class ParamPackMatcher : public TypeListPackMatcher<AnyFunctionType::Param> {
public:
ParamPackMatcher(ArrayRef<AnyFunctionType::Param> lhsParams,
ArrayRef<AnyFunctionType::Param> rhsParams, ASTContext &ctx)
: TypeListPackMatcher(ctx, lhsParams, rhsParams) {}
ParamPackMatcher(
ArrayRef<AnyFunctionType::Param> lhsParams,
ArrayRef<AnyFunctionType::Param> rhsParams, ASTContext &ctx,
std::function<bool(Type)> isPackExpansionType =
[](Type T) { return T->is<PackExpansionType>(); })
: TypeListPackMatcher(ctx, lhsParams, rhsParams, isPackExpansionType) {}
};

/// Performs a structural match of two lists of types.
Expand All @@ -248,8 +253,11 @@ class ParamPackMatcher : public TypeListPackMatcher<AnyFunctionType::Param> {
/// other side.
class PackMatcher : public TypeListPackMatcher<Type> {
public:
PackMatcher(ArrayRef<Type> lhsTypes, ArrayRef<Type> rhsTypes, ASTContext &ctx)
: TypeListPackMatcher(ctx, lhsTypes, rhsTypes) {}
PackMatcher(
ArrayRef<Type> lhsTypes, ArrayRef<Type> rhsTypes, ASTContext &ctx,
std::function<bool(Type)> isPackExpansionType =
[](Type T) { return T->is<PackExpansionType>(); })
: TypeListPackMatcher(ctx, lhsTypes, rhsTypes, isPackExpansionType) {}
};

} // end namespace swift
Expand Down
10 changes: 7 additions & 3 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,12 +400,12 @@ class alignas(1 << TypeAlignInBits) TypeBase
NumProtocols : 16
);

SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 6+32,
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+31,
/// Type variable options.
Options : 6,
Options : 7,
: NumPadBits,
/// The unique number assigned to this type variable.
ID : 32
ID : 31
);

SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+4+1+2+1+1,
Expand Down Expand Up @@ -2459,6 +2459,10 @@ class TupleType final : public TypeBase, public llvm::FoldingSetNode,

bool containsPackExpansionType() const;

/// Check whether this tuple consists of a single unlabeled element
/// of \c PackExpansionType.
bool isSingleUnlabeledPackExpansion() const;

private:
TupleType(ArrayRef<TupleTypeElt> elements, const ASTContext *CanCtx,
RecursiveTypeProperties properties)
Expand Down
65 changes: 65 additions & 0 deletions include/swift/Sema/CSFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,13 @@ enum class FixKind : uint8_t {

/// Allow pack expansion expressions in a context that does not support them.
AllowInvalidPackExpansion,

/// Allow a pack expansion parameter of N elements to be matched
/// with a single tuple literal argument of the same arity.
DestructureTupleToMatchPackExpansionParameter,

/// Allow value pack expansion without pack references.
AllowValueExpansionWithoutPackReferences,
};

class ConstraintFix {
Expand Down Expand Up @@ -3416,6 +3423,64 @@ class AllowGlobalActorMismatch final : public ContextualMismatch {
}
};

/// Passing an argument of tuple type to a value pack expansion parameter
/// that expected N distinct elements.
class DestructureTupleToMatchPackExpansionParameter final
: public ConstraintFix {
PackType *ParamShape;

DestructureTupleToMatchPackExpansionParameter(ConstraintSystem &cs,
PackType *paramShapeTy,
ConstraintLocator *locator)
: ConstraintFix(cs,
FixKind::DestructureTupleToMatchPackExpansionParameter,
locator),
ParamShape(paramShapeTy) {
assert(locator->isLastElement<LocatorPathElt::ApplyArgToParam>());
}

public:
std::string getName() const override {
return "allow pack expansion to match tuple argument";
}

bool diagnose(const Solution &solution, bool asNote = false) const override;

static DestructureTupleToMatchPackExpansionParameter *
create(ConstraintSystem &cs, PackType *paramShapeTy,
ConstraintLocator *locator);

static bool classof(const ConstraintFix *fix) {
return fix->getKind() ==
FixKind::DestructureTupleToMatchPackExpansionParameter;
}
};

class AllowValueExpansionWithoutPackReferences final : public ConstraintFix {
AllowValueExpansionWithoutPackReferences(ConstraintSystem &cs,
ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::AllowValueExpansionWithoutPackReferences,
locator) {}

public:
std::string getName() const override {
return "allow value pack expansion without pack references";
}

bool diagnose(const Solution &solution, bool asNote = false) const override;

bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
return diagnose(*commonFixes.front().first);
}

static AllowValueExpansionWithoutPackReferences *
create(ConstraintSystem &cs, ConstraintLocator *locator);

static bool classof(const ConstraintFix *fix) {
return fix->getKind() == FixKind::AllowValueExpansionWithoutPackReferences;
}
};

} // end namespace constraints
} // end namespace swift

Expand Down
3 changes: 3 additions & 0 deletions include/swift/Sema/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ enum class ConstraintKind : char {
/// an overload. The second type is a PackType containing the explicit
/// generic arguments.
ExplicitGenericArguments,
/// Both (first and second) pack types should have the same reduced shape.
SameShape,
};

/// Classification of the different kinds of constraints.
Expand Down Expand Up @@ -701,6 +703,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
case ConstraintKind::DefaultClosureType:
case ConstraintKind::UnresolvedMemberChainBase:
case ConstraintKind::PackElementOf:
case ConstraintKind::SameShape:
return ConstraintClassification::Relational;

case ConstraintKind::ValueMember:
Expand Down
16 changes: 16 additions & 0 deletions include/swift/Sema/ConstraintLocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,22 @@ class LocatorPathElt::AnyPatternDecl final
}
};

class LocatorPathElt::PackExpansionType final
: public StoredPointerElement<swift::PackExpansionType> {
public:
PackExpansionType(swift::PackExpansionType *openedPackExpansionTy)
: StoredPointerElement(PathElementKind::PackExpansionType,
openedPackExpansionTy) {
assert(openedPackExpansionTy);
}

swift::PackExpansionType *getOpenedType() const { return getStoredPointer(); }

static bool classof(const LocatorPathElt *elt) {
return elt->getKind() == PathElementKind::PackExpansionType;
}
};

namespace details {
template <typename CustomPathElement>
class PathElement {
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Sema/ConstraintLocatorPathElts.def
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ CUSTOM_LOCATOR_PATH_ELT(PackElement)
/// The shape of a parameter pack.
SIMPLE_LOCATOR_PATH_ELT(PackShape)

/// The type of an "opened" pack expansion
CUSTOM_LOCATOR_PATH_ELT(PackExpansionType)

/// The pattern of a pack expansion.
SIMPLE_LOCATOR_PATH_ELT(PackExpansionPattern)

Expand Down
Loading