// 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 #include "executable_semantics/interpreter/impl_scope.h" #include "executable_semantics/interpreter/type_checker.h" #include "executable_semantics/interpreter/value.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Casting.h" using llvm::cast; namespace Carbon { void ImplScope::Add(Nonnull iface, Nonnull type, Nonnull impl) { Add(iface, {}, type, {}, impl); } void ImplScope::Add(Nonnull iface, llvm::ArrayRef> deduced, Nonnull type, llvm::ArrayRef> impl_bindings, Nonnull impl) { impls_.push_back({.interface = iface, .deduced = deduced, .type = type, .impl_bindings = impl_bindings, .impl = impl}); } void ImplScope::AddParent(Nonnull parent) { parent_scopes_.push_back(parent); } auto ImplScope::Resolve(Nonnull iface_type, Nonnull type, SourceLocation source_loc, const TypeChecker& type_checker) const -> ErrorOr> { ASSIGN_OR_RETURN( std::optional> result, TryResolve(iface_type, type, source_loc, *this, type_checker)); if (!result.has_value()) { return CompilationError(source_loc) << "could not find implementation of " << *iface_type << " for " << *type; } return *result; } auto ImplScope::TryResolve(Nonnull iface_type, Nonnull type, SourceLocation source_loc, const ImplScope& original_scope, const TypeChecker& type_checker) const -> ErrorOr>> { ASSIGN_OR_RETURN( std::optional> result, ResolveHere(iface_type, type, source_loc, original_scope, type_checker)); for (Nonnull parent : parent_scopes_) { ASSIGN_OR_RETURN(std::optional> parent_result, parent->TryResolve(iface_type, type, source_loc, original_scope, type_checker)); if (parent_result.has_value()) { if (result.has_value()) { return CompilationError(source_loc) << "ambiguous implementations of " << *iface_type << " for " << *type; } else { result = *parent_result; } } } return result; } auto ImplScope::ResolveHere(Nonnull iface_type, Nonnull impl_type, SourceLocation source_loc, const ImplScope& original_scope, const TypeChecker& type_checker) const -> ErrorOr>> { if (iface_type->kind() != Value::Kind::InterfaceType) { FATAL() << "expected an interface, not " << *iface_type; } const auto& iface = cast(*iface_type); std::optional> result = std::nullopt; for (const Impl& impl : impls_) { std::optional> m = type_checker.MatchImpl( iface, impl_type, impl, original_scope, source_loc); if (m.has_value()) { if (result.has_value()) { return CompilationError(source_loc) << "ambiguous implementations of " << *iface_type << " for " << *impl_type; } else { result = *m; } } } return result; } // TODO: Add indentation when printing the parents. void ImplScope::Print(llvm::raw_ostream& out) const { out << "impls: "; llvm::ListSeparator sep; for (const Impl& impl : impls_) { out << sep << *(impl.type) << " as " << *(impl.interface); } out << "\n"; for (const Nonnull& parent : parent_scopes_) { out << *parent; } } } // namespace Carbon