// 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_MATCHING_IMPL_SET_H_ #define CARBON_EXPLORER_INTERPRETER_MATCHING_IMPL_SET_H_ #include #include "common/ostream.h" #include "explorer/ast/declaration.h" #include "explorer/ast/value.h" #include "explorer/base/nonnull.h" #include "explorer/interpreter/impl_scope.h" #include "llvm/ADT/DenseMap.h" namespace Carbon { // A set of impl matches that we're currently performing. Each `Match` // represents an attempt to match a `type as interface` query against an `impl` // declaration. This is used to detect and reject non-termination when impl // matching recursively triggers further impl matching. // // The language rule we use to detect potential non-termination is to count the // number of times each "label" appears within the type and interface, where a // label is the name of a declared entity such as a class or interface, or a // primitive like `type` or `bool`. For example, `Optional(i32*)` contains the // labels for `Optional`, `i32`, and `*` (built-in pointer type) once each. If // we ever try matching the same `impl` twice, where the inner match contains // at least as many appearances of each label as the outer match, we reject the // program as invalid. We also reject if a query results in the exact same // query being performed again. // // This class is an implementation detail of `TypeChecker::MatchImpl`. class MatchingImplSet { private: class LeafCollector; enum class Label : int; using Signature = llvm::DenseMap; public: // An RAII type that tracks an impl match that we're currently performing. // One instance of this class will exist for each in-progress call to // `MatchImpl`. class Match { public: explicit Match(Nonnull parent, Nonnull impl, Nonnull type, Nonnull interface); ~Match(); Match(const Match&) = delete; auto operator=(const Match&) -> Match& = delete; // Check to see if this match duplicates any prior one within the same set, // or if there's a simpler form of this match in the set. If so, returns a // suitable error. This should be delayed until we know that the impl // structurally matches the type and interface. auto DiagnosePotentialCycle(SourceLocation source_loc) -> ErrorOr; private: friend class LeafCollector; // The set that this match is part of. Nonnull parent_; // The `impl` that is being matched against. Nonnull impl_; // The type that is being matched against the impl. Nonnull type_; // The interface that is being matched against the impl. Nonnull interface_; // The number of times each label appears in the type or interface. Signature signature_; }; private: friend class llvm::DenseMapInfo