Skip to content

Preliminary constraint solver support for variadic generics #61465

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 21 commits into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d9cf85d
AST: Relax an invariant in PackExpansionType::get()
slavapestov Sep 29, 2022
b3c16ea
AST: Tweak printing of PackType and PackExpansionType
slavapestov Sep 29, 2022
b9662f1
AST: Don't need to call getCanonicalType() in TypeBase::isPlaceholder()
slavapestov Oct 5, 2022
fec6c06
AST: TupleType::get() asserts if pack expansion type is followed by a…
slavapestov Oct 5, 2022
4733988
AST: Add TupleType::containsPackExpansionType() utility method
slavapestov Oct 5, 2022
f81a0d9
AST: Introduce AnyFunctionType::containsPackExpansionType()
slavapestov Oct 6, 2022
9ae9c36
Sema: Remove unnecessary overload of computeTupleShuffle()
slavapestov Sep 22, 2022
bbaee23
Sema: Preliminary support for matching tuple types containing pack ex…
slavapestov Sep 22, 2022
9d16b82
AST: Move Sema's TuplePackMatcher to AST
slavapestov Oct 5, 2022
a000b78
AST: Introduce ParamPackMatcher, for structural matching of function …
slavapestov Oct 6, 2022
7e9995b
Sema: Use ParamPackMatcher in matchFunctionTypes()
slavapestov Oct 6, 2022
a10dc8e
AST: New ParameterPack.cpp file with new algorithms for pack expansio…
slavapestov Oct 14, 2022
d4136e9
RequirementMachine: Fix unused variable warning
slavapestov Oct 14, 2022
ee8f45c
Sema: More useful 'unhandled coercion' assertion
slavapestov Oct 14, 2022
5a9e43e
AST: Re-implement transformWithPosition()'s handling of pack expansio…
slavapestov Oct 14, 2022
0653328
Sema: Tests for matching function types containing pack expansion types
slavapestov Oct 14, 2022
0dfdf1c
Sema: Remove unused function prototype
slavapestov Oct 14, 2022
a5453f1
AST: Add new variant of swift::getParameterAt() which takes pack expa…
slavapestov Oct 14, 2022
da8ae1d
Sema: Remove PackExpr
slavapestov Oct 14, 2022
55210f6
Sema: Introduce TVO_CanBindToPack type variable flag
slavapestov Oct 14, 2022
b9d7201
Update test/Constraints/pack_expansion_types.swift for new syntax
slavapestov Oct 17, 2022
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
4 changes: 4 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8399,6 +8399,10 @@ ParameterList *getParameterList(ValueDecl *source);
/// there is none.
ParameterList *getParameterList(DeclContext *source);

/// Retrieve parameter declaration from the given source at given index, or
/// nullptr if the source does not have a parameter list.
const ParamDecl *getParameterAt(ConcreteDeclRef declRef, unsigned index);

/// Retrieve parameter declaration from the given source at given index, or
/// nullptr if the source does not have a parameter list.
const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);
Expand Down
54 changes: 0 additions & 54 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,6 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
IsPlaceholder : 1
);

SWIFT_INLINE_BITFIELD_FULL(PackExpr, Expr, 32,
: NumPadBits,
NumElements : 32
);

SWIFT_INLINE_BITFIELD_FULL(TypeJoinExpr, Expr, 32,
: NumPadBits,
NumElements : 32
Expand Down Expand Up @@ -5908,55 +5903,6 @@ class OneWayExpr : public Expr {
}
};

/// An expression node that aggregates a set of heterogeneous arguments into a
/// parameter pack suitable for passing off to a variadic generic function
/// argument.
///
/// There is no user-visible way to spell a pack expression, they are always
/// implicitly created at applies. As such, any appearance of pack types outside
/// of applies are illegal.
class PackExpr final : public Expr,
private llvm::TrailingObjects<PackExpr, Expr *> {
friend TrailingObjects;

size_t numTrailingObjects() const {
return getNumElements();
}

PackExpr(ArrayRef<Expr *> SubExprs, Type Ty);

public:
/// Create a pack.
static PackExpr *create(ASTContext &ctx, ArrayRef<Expr *> SubExprs, Type Ty);

/// Create an empty pack.
static PackExpr *createEmpty(ASTContext &ctx);

SourceLoc getLoc() const { return SourceLoc(); }
SourceRange getSourceRange() const { return SourceRange(); }

/// Retrieve the elements of this pack.
MutableArrayRef<Expr *> getElements() {
return { getTrailingObjects<Expr *>(), getNumElements() };
}

/// Retrieve the elements of this pack.
ArrayRef<Expr *> getElements() const {
return { getTrailingObjects<Expr *>(), getNumElements() };
}

unsigned getNumElements() const { return Bits.PackExpr.NumElements; }

Expr *getElement(unsigned i) const {
return getElements()[i];
}
void setElement(unsigned i, Expr *e) {
getElements()[i] = e;
}

static bool classof(const Expr *E) { return E->getKind() == ExprKind::Pack; }
};

class TypeJoinExpr final : public Expr,
private llvm::TrailingObjects<TypeJoinExpr, Expr *> {
friend TrailingObjects;
Expand Down
1 change: 0 additions & 1 deletion include/swift/AST/ExprNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ EXPR(KeyPath, Expr)
UNCHECKED_EXPR(KeyPathDot, Expr)
UNCHECKED_EXPR(OneWay, Expr)
EXPR(Tap, Expr)
EXPR(Pack, Expr)
UNCHECKED_EXPR(TypeJoin, Expr)
LAST_EXPR(TypeJoin)

Expand Down
90 changes: 90 additions & 0 deletions include/swift/AST/PackExpansionMatcher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//===--- PackExpansionMatcher.h - Matching pack expansions ------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Utilities for structural matching of sequences of types containing pack
// expansions.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_AST_PACK_EXPANSION_MATCHER_H
#define SWIFT_AST_PACK_EXPANSION_MATCHER_H

#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"

namespace swift {

class ASTContext;

/// The result of a match. If one of lhs or rhs is a pack expansion type,
/// the other one is a pack type.
struct MatchedPair {
Type lhs;
Type rhs;

// An index into the original left-hand side.
unsigned idx;

MatchedPair(Type lhs, Type rhs, unsigned idx)
: lhs(lhs), rhs(rhs), idx(idx) {}
};

/// Performs a structural match of two lists of tuple elements. The invariant
/// is that a pack expansion type must not be followed by an unlabeled
/// element, that is, it is either the last element or the next element has
/// a label.
///
/// In this manner, an element with a pack expansion type "absorbs" all
/// unlabeled elements up to the next label. An element with any other type
/// matches exactly one element on the other side.
class TuplePackMatcher {
ArrayRef<TupleTypeElt> lhsElts;
ArrayRef<TupleTypeElt> rhsElts;

ASTContext &ctx;

public:
SmallVector<MatchedPair, 4> pairs;

TuplePackMatcher(TupleType *lhsTuple, TupleType *rhsTuple);

bool match();
};

/// Performs a structural match of two lists of (unlabeled) function
/// parameters.
///
/// The invariant is that each list must only contain at most one pack
/// expansion type. After collecting a common prefix and suffix, the
/// pack expansion on either side asborbs the remaining elements on the
/// other side.
class ParamPackMatcher {
ArrayRef<AnyFunctionType::Param> lhsParams;
ArrayRef<AnyFunctionType::Param> rhsParams;

ASTContext &ctx;

public:
SmallVector<MatchedPair, 4> pairs;

ParamPackMatcher(ArrayRef<AnyFunctionType::Param> lhsParams,
ArrayRef<AnyFunctionType::Param> rhsParams,
ASTContext &ctx);

bool match();
};

} // end namespace swift

#endif // SWIFT_AST_TYPE_MATCHER_H
4 changes: 4 additions & 0 deletions include/swift/AST/ParameterList.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

namespace swift {

class SubstitutionMap;

/// This describes a list of parameters. Each parameter descriptor is tail
/// allocated onto this list.
class alignas(ParamDecl *) ParameterList final :
Expand Down Expand Up @@ -134,6 +136,8 @@ class alignas(ParamDecl *) ParameterList final :
/// based on the interface types of the parameters in this list.
void getParams(SmallVectorImpl<AnyFunctionType::Param> &params) const;

unsigned getOrigParamIndex(SubstitutionMap subMap, unsigned substIndex) const;

/// Return the full source range of this parameter.
SourceRange getSourceRange() const;
SourceLoc getStartLoc() const { return getSourceRange().Start; }
Expand Down
18 changes: 16 additions & 2 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,9 +384,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
NumProtocols : 16
);

SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 5+32,
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 6+32,
/// Type variable options.
Options : 5,
Options : 6,
: NumPadBits,
/// The unique number assigned to this type variable.
ID : 32
Expand Down Expand Up @@ -2323,6 +2323,10 @@ class TupleType final : public TypeBase, public llvm::FoldingSetNode,
static void Profile(llvm::FoldingSetNodeID &ID,
ArrayRef<TupleTypeElt> Elements);

bool containsPackExpansionType() const;

TupleType *flattenPackTypes();

private:
TupleType(ArrayRef<TupleTypeElt> elements, const ASTContext *CanCtx,
RecursiveTypeProperties properties)
Expand Down Expand Up @@ -3357,6 +3361,10 @@ class AnyFunctionType : public TypeBase {
/// replaced.
AnyFunctionType *withExtInfo(ExtInfo info) const;

static bool containsPackExpansionType(ArrayRef<Param> params);

AnyFunctionType *flattenPackTypes();

static void printParams(ArrayRef<Param> Params, raw_ostream &OS,
const PrintOptions &PO = PrintOptions());
static void printParams(ArrayRef<Param> Params, ASTPrinter &Printer,
Expand Down Expand Up @@ -6410,6 +6418,10 @@ class PackType final : public TypeBase, public llvm::FoldingSetNode,
return getTrailingObjects<Type>()[index];
}

bool containsPackExpansionType() const;

PackType *flattenPackTypes();

public:
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, getElementTypes());
Expand Down Expand Up @@ -6480,6 +6492,8 @@ class PackExpansionType : public TypeBase, public llvm::FoldingSetNode {
/// Retrieves the count type of this pack expansion.
Type getCountType() const { return countType; }

PackExpansionType *expand();

public:
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getPatternType(), getCountType());
Expand Down
40 changes: 15 additions & 25 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@ enum TypeVariableOptions {
/// Whether a more specific deduction for this type variable implies a
/// better solution to the constraint system.
TVO_PrefersSubtypeBinding = 0x10,

/// Whether the type variable can be bound to a pack type or not.
TVO_CanBindToPack = 0x20,
};

/// The implementation object for a type variable used within the
Expand Down Expand Up @@ -387,18 +390,21 @@ class TypeVariableType::Implementation {
&& "Truncation");
}

/// Whether this type variable can bind to an lvalue type.
/// Whether this type variable can bind to an LValueType.
bool canBindToLValue() const { return getRawOptions() & TVO_CanBindToLValue; }

/// Whether this type variable can bind to an inout type.
/// Whether this type variable can bind to an InOutType.
bool canBindToInOut() const { return getRawOptions() & TVO_CanBindToInOut; }

/// Whether this type variable can bind to an inout type.
/// Whether this type variable can bind to a noescape FunctionType.
bool canBindToNoEscape() const { return getRawOptions() & TVO_CanBindToNoEscape; }

/// Whether this type variable can bind to a hole.
/// Whether this type variable can bind to a PlaceholderType.
bool canBindToHole() const { return getRawOptions() & TVO_CanBindToHole; }

/// Whether this type variable can bind to a PackType.
bool canBindToPack() const { return getRawOptions() & TVO_CanBindToPack; }

/// Whether this type variable prefers a subtype binding over a supertype
/// binding.
bool prefersSubtypeBinding() const {
Expand Down Expand Up @@ -638,6 +644,7 @@ class TypeVariableType::Implementation {
ENTRY(TVO_CanBindToNoEscape, "noescape");
ENTRY(TVO_CanBindToHole, "hole");
ENTRY(TVO_PrefersSubtypeBinding, "");
ENTRY(TVO_CanBindToPack, "pack");
}
#undef ENTRY
}
Expand Down Expand Up @@ -5197,15 +5204,6 @@ class ConstraintSystem {
ConstraintKind kind, TypeMatchOptions flags,
ConstraintLocatorBuilder locator);

/// Subroutine of \c matchTypes(), which matches a scalar type to
/// a tuple type.
///
/// \returns the result of performing the scalar-to-tuple conversion.
TypeMatchResult matchScalarToTupleTypes(Type type1, TupleType *tuple2,
ConstraintKind kind,
TypeMatchOptions flags,
ConstraintLocatorBuilder locator);

/// Subroutine of \c matchTypes(), which matches up two function
/// types.
TypeMatchResult matchFunctionTypes(FunctionType *func1, FunctionType *func2,
Expand Down Expand Up @@ -6083,27 +6081,19 @@ class HandlePlaceholderType {
/// Compute the shuffle required to map from a given tuple type to
/// another tuple type.
///
/// \param fromTuple The tuple type we're converting from, as represented by its
/// TupleTypeElt members.
/// \param fromTuple The tuple type we're converting from.
///
/// \param toTuple The tuple type we're converting to, as represented by its
/// TupleTypeElt members.
/// \param toTuple The tuple type we're converting to.
///
/// \param sources Will be populated with information about the source of each
/// of the elements for the result tuple. The indices into this array are the
/// indices of the tuple type we're converting to, while the values are
/// an index into the source tuple.
///
/// \returns true if no tuple conversion is possible, false otherwise.
bool computeTupleShuffle(ArrayRef<TupleTypeElt> fromTuple,
ArrayRef<TupleTypeElt> toTuple,
bool computeTupleShuffle(TupleType *fromTuple,
TupleType *toTuple,
SmallVectorImpl<unsigned> &sources);
static inline bool computeTupleShuffle(TupleType *fromTuple,
TupleType *toTuple,
SmallVectorImpl<unsigned> &sources){
return computeTupleShuffle(fromTuple->getElements(), toTuple->getElements(),
sources);
}

/// Class used as the base for listeners to the \c matchCallArguments process.
///
Expand Down
17 changes: 16 additions & 1 deletion lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3135,6 +3135,15 @@ TupleType *TupleType::get(ArrayRef<TupleTypeElt> Fields, const ASTContext &C) {
properties |= eltTy->getRecursiveProperties();
}

// Enforce an invariant.
for (unsigned i = 0, e = Fields.size(); i < e; ++i) {
if (Fields[i].getType()->is<PackExpansionType>()) {
assert(i == e - 1 || Fields[i + 1].hasName() &&
"Tuple element with pack expansion type cannot be followed "
"by an unlabeled element");
}
}

auto arena = getArena(properties);

void *InsertPos = nullptr;
Expand Down Expand Up @@ -3173,8 +3182,14 @@ PackExpansionType::PackExpansionType(Type patternType, Type countType,
const ASTContext *canCtx)
: TypeBase(TypeKind::PackExpansion, canCtx, properties),
patternType(patternType), countType(countType) {
assert(countType->is<TypeVariableType>() ||

// TODO: it would be nice if the solver didn't stick PlaceholderTypes and
// UnresolvedTypes in here.
assert(countType->is<PackType>() ||
countType->is<TypeVariableType>() ||
countType->is<PackArchetypeType>() ||
countType->is<PlaceholderType>() ||
countType->is<UnresolvedType>() ||
countType->castTo<GenericTypeParamType>()->isParameterPack());
}

Expand Down
Loading