Skip to content

[5.9] [CS] Allow ExprPatterns to be type-checked in the solver #65348

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 24 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c936b27
Revert "[AST] Added hasConcretePack recursive property."
hamishknight Jun 6, 2023
76dedb3
[Parse] Recover slightly better from bad shorthand `if let`
hamishknight May 24, 2023
a8a0fa9
[CS] NFC: Factor out `AllowAssociatedValueMismatch`
hamishknight May 24, 2023
ae8f1aa
[AST] Allocate PlaceholderTypes in the correct arena
hamishknight May 24, 2023
2f64b7f
[CS] Fix `IgnoreUnresolvedPatternVar::diagnose` such that it returns …
hamishknight May 24, 2023
03e5c9f
[CS] A couple of minor improvements to operator diagnostics
hamishknight May 24, 2023
17d8f1f
[CS] Remove obsolete check for a type variable
hamishknight May 24, 2023
02aafea
[CS] Remove invalid DependentMemberType workaround for tuples
hamishknight May 24, 2023
f30202e
[CS] Improve handling of holes for Named/AnyPatterns
hamishknight May 24, 2023
04684b0
Revert "[AST] Allocate PlaceholderTypes in the correct arena"
hamishknight May 24, 2023
8251c8f
[test] Update test for placeholder revert
hamishknight May 24, 2023
3bc14bb
[AST] Allocate PlaceholderTypes in the correct arena
hamishknight May 24, 2023
a35a43f
[CS] Fix a couple of constraints in `getTypeForPattern`
hamishknight Jun 2, 2023
c853611
[CS] Reverse the type order in a couple of pattern equality constraints
hamishknight Jun 2, 2023
43d2547
[CS] Remove external type logic from `getTypeForPattern`
hamishknight Jun 2, 2023
28a4d45
[CS] Remove null pattern handling from `getTypeForPattern`
hamishknight Jun 2, 2023
3a32eb4
[CS] Remove null Type handling from `getTypeForPattern`
hamishknight Jun 2, 2023
9a8503d
[Sema] Walk SyntacticElementTarget for completion
hamishknight Jun 2, 2023
ef211c6
[CS] Allow ExprPatterns to be type-checked in the solver
hamishknight Jun 2, 2023
695f557
[CS] Don't form conversion between switch subject and pattern
hamishknight Jun 2, 2023
77363cc
[CS] Improve diagnostics a bit for pattern mismatch
hamishknight Jun 2, 2023
57169f2
[CS] Fix `coercePatternToType` enum cast handling
hamishknight Jun 2, 2023
05ff1a4
[AST] Added hasConcretePack recursive property.
nate-chandler Jun 2, 2023
7611705
[test] Add test case that exercises lots of `~=` overloads
hamishknight Jun 6, 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
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ ERROR(cannot_match_expr_tuple_pattern_with_nontuple_value,none,
ERROR(cannot_match_unresolved_expr_pattern_with_value,none,
"pattern cannot match values of type %0",
(Type))
ERROR(cannot_match_value_with_pattern,none,
"pattern of type %1 cannot match %0",
(Type, Type))

ERROR(cannot_reference_compare_types,none,
"cannot check reference equality of functions; operands here have types "
Expand Down
27 changes: 22 additions & 5 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,14 @@ class RecursiveTypeProperties {
/// This type contains an ElementArchetype.
HasElementArchetype = 0x4000,

/// Whether the type is allocated in the constraint solver arena. This can
/// differ from \c HasTypeVariable for types such as placeholders, which do
/// not have type variables, but we still want to allocate in the solver if
/// they have a type variable originator.
SolverAllocated = 0x8000,

/// This type contains a concrete pack.
HasConcretePack = 0x8000,
HasConcretePack = 0x10000,

Last_Property = HasConcretePack
};
Expand Down Expand Up @@ -227,6 +233,12 @@ class RecursiveTypeProperties {
/// opened element archetype?
bool hasElementArchetype() const { return Bits & HasElementArchetype; }

/// Whether the type is allocated in the constraint solver arena. This can
/// differ from \c hasTypeVariable() for types such as placeholders, which
/// do not have type variables, but we still want to allocate in the solver if
/// they have a type variable originator.
bool isSolverAllocated() const { return Bits & SolverAllocated; }

/// Does a type with these properties structurally contain a local
/// archetype?
bool hasLocalArchetype() const {
Expand Down Expand Up @@ -405,12 +417,12 @@ class alignas(1 << TypeAlignInBits) TypeBase
NumProtocols : 16
);

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

SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+4+1+2+1+1,
Expand Down Expand Up @@ -506,6 +518,8 @@ class alignas(1 << TypeAlignInBits) TypeBase
}

void setRecursiveProperties(RecursiveTypeProperties properties) {
assert(!(properties.hasTypeVariable() && !properties.isSolverAllocated()) &&
"type variables must be solver allocated!");
Bits.TypeBase.Properties = properties.getBits();
assert(Bits.TypeBase.Properties == properties.getBits() && "Bits dropped!");
}
Expand Down Expand Up @@ -6726,8 +6740,9 @@ TypeVariableType : public TypeBase {
// type is opaque.

TypeVariableType(const ASTContext &C, unsigned ID)
: TypeBase(TypeKind::TypeVariable, &C,
RecursiveTypeProperties::HasTypeVariable) {
: TypeBase(TypeKind::TypeVariable, &C,
RecursiveTypeProperties::HasTypeVariable |
RecursiveTypeProperties::SolverAllocated) {
// Note: the ID may overflow (current limit is 2^20 - 1).
Bits.TypeVariableType.ID = ID;
if (Bits.TypeVariableType.ID != ID) {
Expand Down Expand Up @@ -6786,6 +6801,8 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(TypeVariableType, Type)
/// because the expression is ambiguous. This type is only used by the
/// constraint solver and transformed into UnresolvedType to be used in AST.
class PlaceholderType : public TypeBase {
// NOTE: If you add a new Type-based originator, you'll need to update the
// recursive property logic in PlaceholderType::get.
using Originator =
llvm::PointerUnion<TypeVariableType *, DependentMemberType *, VarDecl *,
ErrorExpr *, PlaceholderTypeRepr *>;
Expand Down
25 changes: 25 additions & 0 deletions include/swift/Sema/CSFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,9 @@ enum class FixKind : uint8_t {
/// Produce a warning for a tuple label mismatch.
AllowTupleLabelMismatch,

/// Allow an associated value mismatch for an enum element pattern.
AllowAssociatedValueMismatch,

/// Produce an error for not getting a compile-time constant
NotCompileTimeConst,

Expand Down Expand Up @@ -3241,6 +3244,28 @@ class AllowTupleLabelMismatch final : public ContextualMismatch {
}
};

class AllowAssociatedValueMismatch final : public ContextualMismatch {
AllowAssociatedValueMismatch(ConstraintSystem &cs, Type fromType, Type toType,
ConstraintLocator *locator)
: ContextualMismatch(cs, FixKind::AllowAssociatedValueMismatch, fromType,
toType, locator) {}

public:
std::string getName() const override {
return "allow associated value mismatch";
}

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

static AllowAssociatedValueMismatch *create(ConstraintSystem &cs,
Type fromType, Type toType,
ConstraintLocator *locator);

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

class AllowNonOptionalWeak final : public ConstraintFix {
AllowNonOptionalWeak(ConstraintSystem &cs, ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::AllowNonOptionalWeak, locator) {}
Expand Down
13 changes: 7 additions & 6 deletions include/swift/Sema/CompletionContextFinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@

namespace swift {

namespace constraints {
class SyntacticElementTarget;
}

class CompletionContextFinder : public ASTWalker {
enum class ContextKind {
FallbackExpression,
Expand Down Expand Up @@ -53,12 +57,9 @@ class CompletionContextFinder : public ASTWalker {
return MacroWalking::Arguments;
}

/// Finder for completion contexts within the provided initial expression.
CompletionContextFinder(ASTNode initialNode, DeclContext *DC)
: InitialExpr(initialNode.dyn_cast<Expr *>()), InitialDC(DC) {
assert(DC);
initialNode.walk(*this);
};
/// Finder for completion contexts within the provided SyntacticElementTarget.
CompletionContextFinder(constraints::SyntacticElementTarget target,
DeclContext *DC);

/// Finder for completion contexts within the outermost non-closure context of
/// the code completion expression's direct context.
Expand Down
12 changes: 10 additions & 2 deletions include/swift/Sema/ConstraintLocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
#ifndef SWIFT_SEMA_CONSTRAINTLOCATOR_H
#define SWIFT_SEMA_CONSTRAINTLOCATOR_H

#include "swift/Basic/Debug.h"
#include "swift/Basic/LLVM.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/NullablePtr.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
Expand Down Expand Up @@ -313,6 +314,13 @@ class ConstraintLocator : public llvm::FoldingSetNode {
/// branch, and if so, the kind of branch.
Optional<SingleValueStmtBranchKind> isForSingleValueStmtBranch() const;

/// If the locator in question is for a pattern match, returns the pattern,
/// otherwise \c nullptr.
NullablePtr<Pattern> getPatternMatch() const;

/// Whether the locator in question is for a pattern match.
bool isForPatternMatch() const;

/// Returns true if \p locator is ending with either of the following
/// - Member
/// - Member -> KeyPathDynamicMember
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Sema/ConstraintLocatorPathElts.def
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ CUSTOM_LOCATOR_PATH_ELT(TernaryBranch)
/// Performing a pattern patch.
CUSTOM_LOCATOR_PATH_ELT(PatternMatch)

/// The constraint that models the allowed implicit casts for
/// an EnumElementPattern.
SIMPLE_LOCATOR_PATH_ELT(EnumPatternImplicitCastMatch)

/// Points to a particular attribute associated with one of
/// the arguments e.g. `inout` or its type e.g. `@escaping`.
///
Expand Down
35 changes: 35 additions & 0 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,10 @@ class Solution {
llvm::SmallMapVector<const CaseLabelItem *, CaseLabelItemInfo, 4>
caseLabelItems;

/// A map of expressions to the ExprPatterns that they are being solved as
/// a part of.
llvm::SmallMapVector<Expr *, ExprPattern *, 2> exprPatterns;

/// The set of parameters that have been inferred to be 'isolated'.
llvm::SmallVector<ParamDecl *, 2> isolatedParams;

Expand Down Expand Up @@ -1685,6 +1689,16 @@ class Solution {
: nullptr;
}

/// Retrieve the solved ExprPattern that corresponds to provided
/// sub-expression.
NullablePtr<ExprPattern> getExprPatternFor(Expr *E) const {
auto result = exprPatterns.find(E);
if (result == exprPatterns.end())
return nullptr;

return result->second;
}

/// This method implements functionality of `Expr::isTypeReference`
/// with data provided by a given solution.
bool isTypeReference(Expr *E) const;
Expand Down Expand Up @@ -2148,6 +2162,10 @@ class ConstraintSystem {
llvm::SmallMapVector<const CaseLabelItem *, CaseLabelItemInfo, 4>
caseLabelItems;

/// A map of expressions to the ExprPatterns that they are being solved as
/// a part of.
llvm::SmallMapVector<Expr *, ExprPattern *, 2> exprPatterns;

/// The set of parameters that have been inferred to be 'isolated'.
llvm::SmallSetVector<ParamDecl *, 2> isolatedParams;

Expand Down Expand Up @@ -2745,6 +2763,9 @@ class ConstraintSystem {
/// The length of \c caseLabelItems.
unsigned numCaseLabelItems;

/// The length of \c exprPatterns.
unsigned numExprPatterns;

/// The length of \c isolatedParams.
unsigned numIsolatedParams;

Expand Down Expand Up @@ -3166,6 +3187,15 @@ class ConstraintSystem {
caseLabelItems[item] = info;
}

/// Record a given ExprPattern as the parent of its sub-expression.
void setExprPatternFor(Expr *E, ExprPattern *EP) {
assert(E);
assert(EP);
auto inserted = exprPatterns.insert({E, EP}).second;
assert(inserted && "Mapping already defined?");
(void)inserted;
}

Optional<CaseLabelItemInfo> getCaseLabelItemInfo(
const CaseLabelItem *item) const {
auto known = caseLabelItems.find(item);
Expand Down Expand Up @@ -4315,6 +4345,11 @@ class ConstraintSystem {
/// \returns \c true if constraint generation failed, \c false otherwise
bool generateConstraints(SingleValueStmtExpr *E);

/// Generate constraints for an array of ExprPatterns, forming a conjunction
/// that solves each expression in turn.
void generateConstraints(ArrayRef<ExprPattern *> exprPatterns,
ConstraintLocatorBuilder locator);

/// Generate constraints for the given (unchecked) expression.
///
/// \returns a possibly-sanitized expression, or null if an error occurred.
Expand Down
46 changes: 37 additions & 9 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ struct ASTContext::Implementation {
llvm::DenseMap<Type, InOutType*> InOutTypes;
llvm::DenseMap<std::pair<Type, void*>, DependentMemberType *>
DependentMemberTypes;
llvm::DenseMap<void *, PlaceholderType *> PlaceholderTypes;
llvm::DenseMap<Type, DynamicSelfType *> DynamicSelfTypes;
llvm::DenseMap<std::pair<EnumDecl*, Type>, EnumType*> EnumTypes;
llvm::DenseMap<std::pair<StructDecl*, Type>, StructType*> StructTypes;
Expand Down Expand Up @@ -1800,9 +1801,8 @@ bool ASTContext::hadError() const {

/// Retrieve the arena from which we should allocate storage for a type.
static AllocationArena getArena(RecursiveTypeProperties properties) {
bool hasTypeVariable = properties.hasTypeVariable();
return hasTypeVariable ? AllocationArena::ConstraintSolver
: AllocationArena::Permanent;
return properties.isSolverAllocated() ? AllocationArena::ConstraintSolver
: AllocationArena::Permanent;
}

void ASTContext::addSearchPath(StringRef searchPath, bool isFramework,
Expand Down Expand Up @@ -3118,15 +3118,43 @@ Type ErrorType::get(Type originalType) {
void *mem = ctx.Allocate(sizeof(ErrorType) + sizeof(Type),
alignof(ErrorType), arena);
RecursiveTypeProperties properties = RecursiveTypeProperties::HasError;
if (originalProperties.hasTypeVariable())
properties |= RecursiveTypeProperties::HasTypeVariable;

// We need to preserve the solver allocated bit, to ensure any wrapping
// types are solver allocated too.
if (originalProperties.isSolverAllocated())
properties |= RecursiveTypeProperties::SolverAllocated;

return entry = new (mem) ErrorType(ctx, originalType, properties);
}

Type PlaceholderType::get(ASTContext &ctx, Originator originator) {
assert(originator);
return new (ctx, AllocationArena::Permanent)
PlaceholderType(ctx, originator, RecursiveTypeProperties::HasPlaceholder);

auto originatorProps = [&]() -> RecursiveTypeProperties {
if (auto *tv = originator.dyn_cast<TypeVariableType *>())
return tv->getRecursiveProperties();

if (auto *depTy = originator.dyn_cast<DependentMemberType *>())
return depTy->getRecursiveProperties();

return RecursiveTypeProperties();
}();
auto arena = getArena(originatorProps);

auto &cache = ctx.getImpl().getArena(arena).PlaceholderTypes;
auto &entry = cache[originator.getOpaqueValue()];
if (entry)
return entry;

RecursiveTypeProperties properties = RecursiveTypeProperties::HasPlaceholder;

// We need to preserve the solver allocated bit, to ensure any wrapping
// types are solver allocated too.
if (originatorProps.isSolverAllocated())
properties |= RecursiveTypeProperties::SolverAllocated;

entry = new (ctx, arena) PlaceholderType(ctx, originator, properties);
return entry;
}

BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth,
Expand Down Expand Up @@ -3944,7 +3972,7 @@ isAnyFunctionTypeCanonical(ArrayRef<AnyFunctionType::Param> params,
static RecursiveTypeProperties
getGenericFunctionRecursiveProperties(ArrayRef<AnyFunctionType::Param> params,
Type result) {
static_assert(RecursiveTypeProperties::BitWidth == 16,
static_assert(RecursiveTypeProperties::BitWidth == 17,
"revisit this if you add new recursive type properties");
RecursiveTypeProperties properties;

Expand Down Expand Up @@ -4604,7 +4632,7 @@ CanSILFunctionType SILFunctionType::get(
void *mem = ctx.Allocate(bytes, alignof(SILFunctionType));

RecursiveTypeProperties properties;
static_assert(RecursiveTypeProperties::BitWidth == 16,
static_assert(RecursiveTypeProperties::BitWidth == 17,
"revisit this if you add new recursive type properties");
for (auto &param : params)
properties |= param.getInterfaceType()->getRecursiveProperties();
Expand Down
Loading