mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
163 lines
6.2 KiB
C++
163 lines
6.2 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef CARBON_EXPLORER_INTERPRETER_PATTERN_ANALYSIS_H_
|
|
#define CARBON_EXPLORER_INTERPRETER_PATTERN_ANALYSIS_H_
|
|
|
|
#include <vector>
|
|
|
|
#include "explorer/ast/pattern.h"
|
|
#include "explorer/ast/value.h"
|
|
#include "explorer/base/nonnull.h"
|
|
#include "llvm/ADT/PointerUnion.h"
|
|
|
|
namespace Carbon {
|
|
|
|
// An abstracted view of a pattern or constant value (which we view as a
|
|
// particular kind of pattern).
|
|
class AbstractPattern {
|
|
public:
|
|
enum Kind {
|
|
// A pattern that matches anything.
|
|
Wildcard,
|
|
// A pattern that matches a compound value with sub-patterns to match
|
|
// elements. A compound value is modeled as a discriminator name applied to
|
|
// a sequence of nested values: the alternative `Optional.Element(E)` has
|
|
// discriminator `Element` and nested value `E`, and the tuple `(A,B,C)`
|
|
// has an empty discriminator and nested values `A`, `B`, and `C`.
|
|
Compound,
|
|
// A pattern that matches a particular primitive value.
|
|
Primitive
|
|
};
|
|
|
|
// This is intentionally implicit to allow easy conversion from a container
|
|
// of `const Pattern*` to a container of `AbstractPattern`s.
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
AbstractPattern(Nonnull<const Pattern*> pattern) { Set(pattern); }
|
|
|
|
AbstractPattern(Nonnull<const Value*> value, Nonnull<const Value*> type)
|
|
: value_(value), type_(type) {}
|
|
|
|
// Make a match-anything wildcard pattern.
|
|
static auto MakeWildcard() -> AbstractPattern {
|
|
return AbstractPattern(WildcardTag());
|
|
}
|
|
|
|
// Get the kind for this pattern.
|
|
auto kind() const -> Kind;
|
|
|
|
// Get the type, for a non-wildcard pattern.
|
|
auto type() const -> const Value&;
|
|
|
|
// Get the discriminator used for a compound pattern.
|
|
auto discriminator() const -> std::string_view;
|
|
|
|
// Get the number of nested patterns for a compound pattern.
|
|
auto elements_size() const -> int;
|
|
|
|
// Append the nested patterns in this compound pattern to `out`.
|
|
void AppendElementsTo(std::vector<AbstractPattern>& out) const;
|
|
|
|
// Get the value for a primitive pattern.
|
|
auto value() const -> const Value&;
|
|
|
|
private:
|
|
// This is aligned so that we can use it in the `PointerUnion` below.
|
|
struct alignas(8) WildcardTag {};
|
|
explicit AbstractPattern(WildcardTag /*unused*/)
|
|
: value_(static_cast<const WildcardTag*>(nullptr)), type_(nullptr) {}
|
|
|
|
void Set(Nonnull<const Pattern*> pattern);
|
|
|
|
// The underlying pattern: either a syntactic pattern, or a constant value,
|
|
// or a placeholder indicating that this is a wildcard pattern.
|
|
llvm::PointerUnion<Nonnull<const Pattern*>, Nonnull<const Value*>,
|
|
const WildcardTag*>
|
|
value_;
|
|
// Values don't always know their types, so store the type here. We only
|
|
// really need it for the `const Value*` case but also store it for the
|
|
// `const Pattern*` case for convenience.
|
|
const Value* type_;
|
|
};
|
|
|
|
// A matrix of patterns, used for determining exhaustiveness and redundancy of
|
|
// patterns in a match statement.
|
|
//
|
|
// See http://moscova.inria.fr/~maranget/papers/warn/index.html for details on
|
|
// the algorithm used here.
|
|
class PatternMatrix {
|
|
public:
|
|
// Add a pattern vector row to this collection of pattern vectors.
|
|
void Add(std::vector<AbstractPattern> pattern_vector) {
|
|
CARBON_CHECK(matrix_.empty() || matrix_[0].size() == pattern_vector.size());
|
|
matrix_.push_back(std::move(pattern_vector));
|
|
}
|
|
|
|
// Returns true if the given pattern vector is redundant if it appears after
|
|
// the patterns in this matrix. That is, if it will never match following the
|
|
// other patterns because everything it matches is matched by some other
|
|
// pattern.
|
|
auto IsRedundant(llvm::ArrayRef<AbstractPattern> pattern) const -> bool {
|
|
return !IsUseful(pattern, MaxExponentialDepth);
|
|
}
|
|
|
|
private:
|
|
// The maximum number of times we will consider all alternatives when
|
|
// recursively expanding the pattern. Allowing this to happen an arbitrary
|
|
// number of times leads to exponential growth in the runtime of the
|
|
// algorithm.
|
|
static constexpr int MaxExponentialDepth = 8;
|
|
|
|
// Information about a constructor for a compound type.
|
|
struct DiscriminatorInfo {
|
|
// For an alternative, the name. Otherwise, empty.
|
|
std::string_view discriminator;
|
|
// The number of elements. For a tuple, the size. Always 1 for an
|
|
// alternative.
|
|
int size;
|
|
};
|
|
|
|
struct DiscriminatorSet {
|
|
std::vector<DiscriminatorInfo> found;
|
|
bool any_missing;
|
|
};
|
|
|
|
// Determine whether the given pattern vector is useful: that is, whether
|
|
// adding it to the matrix would allow any more values to be matched.
|
|
auto IsUseful(llvm::ArrayRef<AbstractPattern> pattern,
|
|
int max_exponential_depth) const -> bool;
|
|
|
|
// Find the discriminators used by the first column and check whether we
|
|
// found all of them.
|
|
auto FirstColumnDiscriminators() const -> DiscriminatorSet;
|
|
|
|
// Specialize the pattern vector `row` for the case that the first value
|
|
// matched uses `discriminator`.
|
|
static auto SpecializeRow(llvm::ArrayRef<AbstractPattern> row,
|
|
DiscriminatorInfo discriminator)
|
|
-> std::optional<std::vector<AbstractPattern>>;
|
|
|
|
// Specialize the pattern matrix for the case that the first value matched
|
|
// uses `discriminator`, and its elements are matched.
|
|
auto Specialize(DiscriminatorInfo discriminator) const -> PatternMatrix;
|
|
|
|
// Specialize the pattern matrix for the case where the first value is known
|
|
// to be `value`, and is not matched.
|
|
auto Specialize(const Value& value) const -> PatternMatrix;
|
|
|
|
// Specialize the pattern matrix for the case where the first value uses a
|
|
// discriminator matching none of the non-wildcard patterns.
|
|
auto Default() const -> PatternMatrix;
|
|
|
|
// The pattern matrix itself, in row-major order. Each element of `matrix_`
|
|
// is a distinct sequence of patterns that can be matched against a
|
|
// corresponding sequence of values. Each such row has the same length and
|
|
// has elements of the same type.
|
|
std::vector<std::vector<AbstractPattern>> matrix_;
|
|
};
|
|
|
|
} // namespace Carbon
|
|
|
|
#endif // CARBON_EXPLORER_INTERPRETER_PATTERN_ANALYSIS_H_
|