Skip to content

[ConstraintSystem] Model pack expansion types via type variables #65125

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 36 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
6769e39
[ConstraintSystem] Add a new locator element to identify pack expansi…
xedin Apr 6, 2023
5c2f77c
[AST] PackMatching: Make pack expansion type check pluggable
xedin Apr 6, 2023
6437531
[ConstraintSystem] Introduce `TVO_PackExpansion`
xedin Apr 6, 2023
39c2bbb
[ConstraintSystem] Implement pack expansion type opening
xedin Apr 6, 2023
c7ef47d
[ConstraintSystem] TypeSimplifier: Prevent flattening of partially re…
xedin Apr 7, 2023
ca534ef
[ConstraintSystem] Handle presence of pack expansion type variables w…
xedin Apr 10, 2023
c130351
[ConstraintSystem] Implement pack expansion variable resolution
xedin Apr 11, 2023
5340725
[CSSimplify] Prevent merging of type expansion type variables
xedin Apr 11, 2023
d7c3208
[CSSimplify] Handle presence of pack expansion if tuples and shape co…
xedin Apr 11, 2023
b0abb7f
[CSSimplify] Delay `.element` lookup if pack expansion is not yet res…
xedin Apr 11, 2023
0738780
[CSSimplify] Introduce `containsPackExpansionType` that handles pack …
xedin Apr 12, 2023
b4ba68a
[AST] `containsPackExpansion` should not be used when type variables …
xedin Apr 12, 2023
2ebade1
[CSSimplify] Delay matching if one of the types is a tuple with unres…
xedin Apr 12, 2023
8a39f3f
[CSBindings] Mark type variables that represent packs as involving ty…
xedin Apr 12, 2023
f4a082d
[ConstraintSystem] TypeSimplifier: If pattern and shape are packs - p…
xedin Apr 12, 2023
5985275
[ConstraintSystem] TypeSimplifier: Unwrap tuple if pack expansion var…
xedin Apr 12, 2023
62b6d01
[ConstraintSystem] Form a special one type binding set for pack expan…
xedin Apr 12, 2023
218ccb1
[ConstraintSystem] Adjust `openType` and `openUnboundGenericType` to …
xedin Apr 12, 2023
cc2b6ce
[CSSimplify] Type matching should maintain tuples when matching types…
xedin Apr 13, 2023
ed23aec
[ConstraintSystem] Record opened pack expansion type in the locator e…
xedin Apr 13, 2023
fd060f5
[ConstraintSystem] Add a locator to `openType` and some of its callers
xedin Apr 14, 2023
9a395f0
[CSSimplify] Merge binding inference logic with `PackElementOf` const…
xedin Apr 18, 2023
9365211
[CSDiagnostics] Teach generic parameter restoration logic about pack …
xedin Apr 20, 2023
38ee650
[CSSimplify] Prevent contextual mismatch diagnostics from seeing one-…
xedin Apr 20, 2023
943ef19
[CSSimplify] Adjust `replaceTypeVariablesWithFreshPacks` to propagate…
xedin Apr 21, 2023
cbfec20
[CSSimplify] Propagate contextual types to pack expansion variables
xedin Apr 24, 2023
bbe305c
[ConstraintSystem] Add `same-shape` constraint
xedin Apr 24, 2023
03f88a0
[CSSimplify] Add tailored diagnostics for same-shape mismatches relat…
xedin Apr 25, 2023
b5aae06
[CSDiagnostics] Unwrap some packs types for diagnostics
xedin Apr 25, 2023
b9ef2ca
[CSFix] Add a skeleton of a fix for argument destructuring to match p…
xedin Apr 25, 2023
c74824e
[CSDiagnostics] Diagnose situations when value pack expansion does ex…
xedin Apr 25, 2023
3006f55
[CSSimplify] Detect and diagnose passing a tuple to pack expansion th…
xedin Apr 25, 2023
0db6746
[CSSimplify] If pack type has holes - its shape is a hole
xedin Apr 26, 2023
d8c8a39
[CSFix] Add a fix to allow value pack expansions without pack references
xedin Apr 27, 2023
cb2fdd9
[CSDiagnostics] Add a diagnostic for pack expansions without pack ref…
xedin Apr 27, 2023
bff6a89
[CSGen] Detect and diagnose invalid pack expansion expressions
xedin Apr 27, 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 @@ -5423,6 +5423,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
6 changes: 3 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
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