Switch executable semantics to use ErrorBuilder directly and relocate macros (#1184)

This commit is contained in:
Jon Meow
2022-04-13 09:05:21 -07:00
committed by GitHub
parent 6542506cdc
commit 87e58f5db3
37 changed files with 327 additions and 376 deletions
+2 -2
View File
@@ -54,8 +54,8 @@ lifetime groups in the future.
For simplicity, `executable_semantics` generally treats all errors as fatal.
Errors caused by bugs in the user-provided Carbon code should be reported with
the macros in [`error.h`](common/error.h). Errors caused by bugs in
`executable_semantics` itself should be reported with
the error builders in [`error_builders.h`](common/error_builders.h). Errors
caused by bugs in `executable_semantics` itself should be reported with
[`CHECK` or `FATAL`](../common/check.h).
## Example Programs (Regression Tests)
+13 -22
View File
@@ -22,7 +22,7 @@ cc_library(
"ast_rtti.h",
],
deps = [
":source_location",
"//executable_semantics/common:source_location",
"@llvm-project//llvm:Support",
],
)
@@ -77,11 +77,11 @@ cc_library(
deps = [
":ast_node",
":pattern",
":source_location",
":value_category",
"//common:check",
"//common:ostream",
"//executable_semantics/common:nonnull",
"//executable_semantics/common:source_location",
"@llvm-project//llvm:Support",
],
)
@@ -97,12 +97,12 @@ cc_library(
":impl_binding",
":pattern",
":return_term",
":source_location",
":statement",
":static_scope",
":value_category",
"//common:ostream",
"//executable_semantics/common:nonnull",
"//executable_semantics/common:source_location",
"@llvm-project//llvm:Support",
],
)
@@ -112,10 +112,10 @@ cc_library(
hdrs = ["return_term.h"],
deps = [
":expression",
":source_location",
"//common:check",
"//common:ostream",
"//executable_semantics/common:nonnull",
"//executable_semantics/common:source_location",
"@llvm-project//llvm:Support",
],
)
@@ -127,13 +127,13 @@ cc_library(
deps = [
":ast_node",
":paren_contents",
":source_location",
":static_scope",
":value_category",
"//common:indirect_value",
"//common:ostream",
"//executable_semantics/common:arena",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:source_location",
"@llvm-project//llvm:Support",
],
)
@@ -159,8 +159,8 @@ cc_library(
name = "paren_contents",
hdrs = ["paren_contents.h"],
deps = [
":source_location",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:source_location",
],
)
@@ -171,12 +171,12 @@ cc_library(
deps = [
":ast_node",
":expression",
":source_location",
":static_scope",
":value_category",
"//common:ostream",
"//executable_semantics/common:arena",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:source_location",
"@llvm-project//llvm:Support",
],
)
@@ -200,25 +200,16 @@ cc_library(
hdrs = ["static_scope.h"],
deps = [
":ast_node",
":source_location",
":value_category",
"//common:check",
"//common:error",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:nonnull",
"//executable_semantics/common:source_location",
"@llvm-project//llvm:Support",
],
)
cc_library(
name = "source_location",
hdrs = ["source_location.h"],
deps = [
"//common:ostream",
"//executable_semantics/common:nonnull",
],
)
cc_library(
name = "statement",
srcs = ["statement.cpp"],
@@ -228,12 +219,12 @@ cc_library(
":expression",
":pattern",
":return_term",
":source_location",
":static_scope",
":value_category",
"//common:check",
"//common:ostream",
"//executable_semantics/common:arena",
"//executable_semantics/common:source_location",
"@llvm-project//llvm:Support",
],
)
+1 -1
View File
@@ -6,7 +6,7 @@
#define EXECUTABLE_SEMANTICS_AST_AST_NODE_H_
#include "executable_semantics/ast/ast_rtti.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/common/source_location.h"
#include "llvm/Support/Casting.h"
namespace Carbon {
+2 -2
View File
@@ -175,14 +175,14 @@ auto FunctionDeclaration::Create(
case AstNodeKind::BindingPattern: {
Nonnull<BindingPattern*> bp = &cast<BindingPattern>(*param);
if (me_pattern.has_value() || bp->name() != "me") {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "illegal binding pattern in implicit parameter list";
}
me_pattern = bp;
break;
}
default:
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "illegal AST node in implicit parameter list";
}
}
+1 -1
View File
@@ -14,11 +14,11 @@
#include "executable_semantics/ast/impl_binding.h"
#include "executable_semantics/ast/pattern.h"
#include "executable_semantics/ast/return_term.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/ast/statement.h"
#include "executable_semantics/ast/static_scope.h"
#include "executable_semantics/ast/value_category.h"
#include "executable_semantics/common/nonnull.h"
#include "executable_semantics/common/source_location.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Compiler.h"
+2 -3
View File
@@ -8,7 +8,7 @@
#include <optional>
#include "executable_semantics/common/arena.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
@@ -26,8 +26,7 @@ auto IntrinsicExpression::FindIntrinsic(std::string_view name,
name.remove_prefix(std::strlen("__intrinsic_"));
auto it = intrinsic_map.find(name);
if (it == intrinsic_map.end()) {
return FATAL_COMPILATION_ERROR(source_loc)
<< "Unknown intrinsic '" << name << "'";
return CompilationError(source_loc) << "Unknown intrinsic '" << name << "'";
}
return it->second;
}
+1 -1
View File
@@ -14,10 +14,10 @@
#include "common/ostream.h"
#include "executable_semantics/ast/ast_node.h"
#include "executable_semantics/ast/paren_contents.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/ast/static_scope.h"
#include "executable_semantics/ast/value_category.h"
#include "executable_semantics/common/arena.h"
#include "executable_semantics/common/source_location.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Compiler.h"
+2 -2
View File
@@ -9,8 +9,8 @@
#include <string>
#include <vector>
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "executable_semantics/common/source_location.h"
namespace Carbon {
+2 -2
View File
@@ -9,7 +9,7 @@
#include "common/ostream.h"
#include "executable_semantics/ast/expression.h"
#include "executable_semantics/common/arena.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
@@ -151,7 +151,7 @@ auto TuplePatternFromParenContents(Nonnull<Arena*> arena,
auto AlternativePattern::RequireFieldAccess(Nonnull<Expression*> alternative)
-> ErrorOr<Nonnull<FieldAccessExpression*>> {
if (alternative->kind() != ExpressionKind::FieldAccessExpression) {
return FATAL_PROGRAM_ERROR(alternative->source_loc())
return ProgramError(alternative->source_loc())
<< "Alternative pattern must have the form of a field access.";
}
return &cast<FieldAccessExpression>(*alternative);
+1 -1
View File
@@ -13,9 +13,9 @@
#include "executable_semantics/ast/ast_node.h"
#include "executable_semantics/ast/ast_rtti.h"
#include "executable_semantics/ast/expression.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/ast/static_scope.h"
#include "executable_semantics/ast/value_category.h"
#include "executable_semantics/common/source_location.h"
#include "llvm/ADT/ArrayRef.h"
namespace Carbon {
+1 -1
View File
@@ -11,8 +11,8 @@
#include "common/check.h"
#include "common/ostream.h"
#include "executable_semantics/ast/expression.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/common/nonnull.h"
#include "executable_semantics/common/source_location.h"
namespace Carbon {
+1 -1
View File
@@ -13,10 +13,10 @@
#include "executable_semantics/ast/expression.h"
#include "executable_semantics/ast/pattern.h"
#include "executable_semantics/ast/return_term.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/ast/static_scope.h"
#include "executable_semantics/ast/value_category.h"
#include "executable_semantics/common/arena.h"
#include "executable_semantics/common/source_location.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Compiler.h"
+4 -5
View File
@@ -4,7 +4,7 @@
#include "executable_semantics/ast/static_scope.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "llvm/Support/Error.h"
namespace Carbon {
@@ -13,7 +13,7 @@ auto StaticScope::Add(std::string name, ValueNodeView entity)
-> ErrorOr<Success> {
auto [it, success] = declared_names_.insert({name, entity});
if (!success && it->second != entity) {
return FATAL_COMPILATION_ERROR(entity.base().source_loc())
return CompilationError(entity.base().source_loc())
<< "Duplicate name `" << name << "` also found at "
<< it->second.base().source_loc();
}
@@ -26,8 +26,7 @@ auto StaticScope::Resolve(const std::string& name,
ASSIGN_OR_RETURN(std::optional<ValueNodeView> result,
TryResolve(name, source_loc));
if (!result) {
return FATAL_COMPILATION_ERROR(source_loc)
<< "could not resolve '" << name << "'";
return CompilationError(source_loc) << "could not resolve '" << name << "'";
}
return *result;
}
@@ -45,7 +44,7 @@ auto StaticScope::TryResolve(const std::string& name,
parent->TryResolve(name, source_loc));
if (parent_result.has_value() && result.has_value() &&
*parent_result != *result) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "'" << name << "' is ambiguous between "
<< result->base().source_loc() << " and "
<< parent_result->base().source_loc();
+1 -1
View File
@@ -14,9 +14,9 @@
#include "common/check.h"
#include "common/error.h"
#include "executable_semantics/ast/ast_node.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/ast/value_category.h"
#include "executable_semantics/common/nonnull.h"
#include "executable_semantics/common/source_location.h"
#include "llvm/Support/Error.h"
namespace Carbon {
+16 -10
View File
@@ -13,23 +13,21 @@ cc_library(
)
cc_library(
name = "error",
hdrs = ["error.h"],
name = "error_builders",
hdrs = ["error_builders.h"],
deps = [
"//common:check",
":source_location",
"//common:error",
"//executable_semantics/ast:source_location",
"@llvm-project//llvm:Support",
],
)
cc_test(
name = "error_test",
srcs = ["error_test.cpp"],
name = "error_builders_test",
srcs = ["error_builders_test.cpp"],
deps = [
":error",
":error_builders",
":source_location",
"@com_google_googletest//:gtest_main",
"@llvm-project//llvm:Support",
],
)
@@ -38,6 +36,14 @@ cc_library(
hdrs = ["nonnull.h"],
deps = [
"//common:check",
"@llvm-project//llvm:Support",
],
)
cc_library(
name = "source_location",
hdrs = ["source_location.h"],
deps = [
":nonnull",
"//common:ostream",
],
)
-109
View File
@@ -1,109 +0,0 @@
// 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 EXECUTABLE_SEMANTICS_COMMON_ERROR_H_
#define EXECUTABLE_SEMANTICS_COMMON_ERROR_H_
#include <optional>
#include "common/check.h"
#include "common/error.h"
#include "executable_semantics/ast/source_location.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
namespace Carbon {
// A helper class for accumulating error message and converting to
// `Carbon::Error`/`Carbon::ErrorOr<T>`.
class ErrorBuilder {
public:
explicit ErrorBuilder(std::optional<SourceLocation> loc = std::nullopt)
: out_(message_) {
if (loc.has_value()) {
out_ << *loc << ": ";
}
}
// Accumulates string message.
template <typename T>
[[nodiscard]] auto operator<<(const T& message) -> ErrorBuilder& {
out_ << message;
return *this;
}
// NOLINTNEXTLINE(google-explicit-constructor): Implicit cast for returns.
operator Error() { return Error(message_); }
template <typename V>
// NOLINTNEXTLINE(google-explicit-constructor): Implicit cast for returns.
operator ErrorOr<V>() {
return Error(message_);
}
std::string message_;
llvm::raw_string_ostream out_;
};
// Builds a Carbon::Error instance with the specified message. This should be
// used for non-recoverable errors with user input.
//
// For example:
// return FATAL_PROGRAM_ERROR(line_num) << "Line is bad!";
// return FATAL_PROGRAM_ERROR_NO_LINE() << "Application is bad!";
//
// Where possible, try to identify the error as a compilation or
// runtime error. Use CHECK/FATAL for internal errors. The generic program
// error option is provided as a fallback for cases that don't fit those
// classifications.
//
// TODO: replace below macro invocations with direct `return ErrorBuilder() <<
// xx` calls.
#define FATAL_PROGRAM_ERROR_NO_LINE() \
Carbon::ErrorBuilder() << "PROGRAM ERROR: "
#define FATAL_PROGRAM_ERROR(line) \
FATAL_PROGRAM_ERROR_NO_LINE() << (line) << ": "
#define FATAL_COMPILATION_ERROR_NO_LINE() \
Carbon::ErrorBuilder() << "COMPILATION ERROR: "
#define FATAL_COMPILATION_ERROR(line) \
FATAL_COMPILATION_ERROR_NO_LINE() << (line) << ": "
#define FATAL_RUNTIME_ERROR_NO_LINE() \
Carbon::ErrorBuilder() << "RUNTIME ERROR: "
#define FATAL_RUNTIME_ERROR(line) \
FATAL_RUNTIME_ERROR_NO_LINE() << (line) << ": "
// Macro hackery to get a unique variable name.
#define MAKE_UNIQUE_NAME_IMPL(a, b, c) a##b##c
#define MAKE_UNIQUE_NAME(a, b, c) MAKE_UNIQUE_NAME_IMPL(a, b, c)
#define RETURN_IF_ERROR_IMPL(unique_name, expr) \
if (auto unique_name = (expr); /* NOLINT(bugprone-macro-parentheses) */ \
!(unique_name).ok()) { \
return std::move(unique_name).error(); \
}
#define RETURN_IF_ERROR(expr) \
RETURN_IF_ERROR_IMPL( \
MAKE_UNIQUE_NAME(_llvm_error_line, __LINE__, __COUNTER__), expr)
#define ASSIGN_OR_RETURN_IMPL(unique_name, var, expr) \
auto unique_name = (expr); /* NOLINT(bugprone-macro-parentheses) */ \
if (!(unique_name).ok()) { \
return std::move(unique_name).error(); \
} \
var = std::move(*(unique_name)); /* NOLINT(bugprone-macro-parentheses) */
#define ASSIGN_OR_RETURN(var, expr) \
ASSIGN_OR_RETURN_IMPL( \
MAKE_UNIQUE_NAME(_llvm_expected_line, __LINE__, __COUNTER__), var, expr)
} // namespace Carbon
#endif // EXECUTABLE_SEMANTICS_COMMON_ERROR_H_
@@ -0,0 +1,44 @@
// 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 EXECUTABLE_SEMANTICS_COMMON_ERROR_BUILDERS_H_
#define EXECUTABLE_SEMANTICS_COMMON_ERROR_BUILDERS_H_
#include "common/error.h"
#include "executable_semantics/common/source_location.h"
namespace Carbon {
// Builds an Error instance with the specified message. This should be used for
// non-recoverable errors with user input.
//
// For example:
// return ProgramError(line_num) << "Line is bad!";
// return ProgramError() << "Application is bad!";
//
// Where possible, try to identify the error as a compilation or runtime error.
// Use CHECK/FATAL for internal errors. The generic program error option is
// provided as a fallback for cases that don't fit those classifications.
inline auto CompilationError(SourceLocation loc) -> ErrorBuilder {
ErrorBuilder builder;
(void)(builder << "COMPILATION ERROR: " << loc << ": ");
return builder;
}
inline auto ProgramError(SourceLocation loc) -> ErrorBuilder {
ErrorBuilder builder;
(void)(builder << "PROGRAM ERROR: " << loc << ": ");
return builder;
}
inline auto RuntimeError(SourceLocation loc) -> ErrorBuilder {
ErrorBuilder builder;
(void)(builder << "RUNTIME ERROR: " << loc << ": ");
return builder;
}
} // namespace Carbon
#endif // EXECUTABLE_SEMANTICS_COMMON_ERROR_BUILDERS_H_
@@ -0,0 +1,30 @@
// 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/common/error_builders.h"
#include <gtest/gtest.h>
#include "executable_semantics/common/source_location.h"
namespace Carbon::Testing {
namespace {
TEST(ErrorBuildersTest, CompilationError) {
Error err = CompilationError(SourceLocation("x", 1)) << "test";
EXPECT_EQ(err.message(), "COMPILATION ERROR: x:1: test");
}
TEST(ErrorBuildersTest, ProgramError) {
Error err = ProgramError(SourceLocation("x", 1)) << "test";
EXPECT_EQ(err.message(), "PROGRAM ERROR: x:1: test");
}
TEST(ErrorBuildersTest, RuntimeError) {
Error err = RuntimeError(SourceLocation("x", 1)) << "test";
EXPECT_EQ(err.message(), "RUNTIME ERROR: x:1: test");
}
} // namespace
} // namespace Carbon::Testing
-101
View File
@@ -1,101 +0,0 @@
// 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/common/error.h"
#include <gtest/gtest.h>
namespace Carbon::Testing {
namespace {
auto MakeSuccess() -> ErrorOr<Success> { return Success(); }
auto MakeError(std::string_view message) -> ErrorOr<Success> {
return Error(message);
}
auto MakeInt(int value) -> ErrorOr<int> { return value; }
auto MakeFailedInt(std::string_view message) -> ErrorOr<int> {
return Error(message);
}
auto ErrorToString(const Error& e) -> std::string { return e.message(); }
template <typename V>
auto ErrorToString(const ErrorOr<V>& e) -> std::string {
return e.error().message();
}
TEST(ErrorTest, FatalProgramError) {
EXPECT_EQ(ErrorToString(FATAL_PROGRAM_ERROR_NO_LINE() << "test"),
"PROGRAM ERROR: test");
}
TEST(ErrorTest, FatalRuntimeError) {
EXPECT_EQ(ErrorToString(FATAL_RUNTIME_ERROR_NO_LINE() << "test"),
"RUNTIME ERROR: test");
}
TEST(ErrorTest, FatalCompilationError) {
EXPECT_EQ(ErrorToString(FATAL_COMPILATION_ERROR_NO_LINE() << "test"),
"COMPILATION ERROR: test");
}
TEST(ErrorTest, FatalProgramErrorLine) {
EXPECT_EQ(ErrorToString(FATAL_PROGRAM_ERROR(1) << "test"),
"PROGRAM ERROR: 1: test");
}
TEST(ErrorTest, ReturnIfErrorNoError) {
auto result = []() -> ErrorOr<Success> {
RETURN_IF_ERROR(MakeSuccess());
RETURN_IF_ERROR(MakeSuccess());
return Success();
}();
EXPECT_TRUE(result.ok());
}
TEST(ErrorTest, ReturnIfErrorHasError) {
auto result = []() -> ErrorOr<Success> {
RETURN_IF_ERROR(MakeSuccess());
RETURN_IF_ERROR(MakeError("error"));
return Success();
}();
ASSERT_FALSE(result.ok());
EXPECT_EQ(ErrorToString(result), "error");
}
TEST(ErrorTest, AssignOrReturnNoError) {
auto result = []() -> ErrorOr<int> {
RETURN_IF_ERROR(MakeSuccess());
ASSIGN_OR_RETURN(int a, MakeInt(1));
ASSIGN_OR_RETURN(const int b, MakeInt(2));
int c = 0;
ASSIGN_OR_RETURN(c, MakeInt(3));
return a + b + c;
}();
ASSERT_TRUE(result.ok());
EXPECT_EQ(6, *result);
}
TEST(ErrorTest, AssignOrReturnHasDirectError) {
auto result = []() -> ErrorOr<int> {
RETURN_IF_ERROR(MakeError("error"));
return 0;
}();
ASSERT_FALSE(result.ok());
}
TEST(ErrorTest, AssignOrReturnHasErrorInExpected) {
auto result = []() -> ErrorOr<int> {
ASSIGN_OR_RETURN(int a, MakeFailedInt("error"));
return a;
}();
ASSERT_FALSE(result.ok());
EXPECT_EQ(ErrorToString(result), "error");
}
} // namespace
} // namespace Carbon::Testing
@@ -2,8 +2,8 @@
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef EXECUTABLE_SEMANTICS_AST_SOURCE_LOCATION_H_
#define EXECUTABLE_SEMANTICS_AST_SOURCE_LOCATION_H_
#ifndef EXECUTABLE_SEMANTICS_COMMON_SOURCE_LOCATION_H_
#define EXECUTABLE_SEMANTICS_COMMON_SOURCE_LOCATION_H_
#include <string>
#include <string_view>
@@ -42,4 +42,4 @@ class SourceLocation {
} // namespace Carbon
#endif // EXECUTABLE_SEMANTICS_AST_SOURCE_LOCATION_H_
#endif // EXECUTABLE_SEMANTICS_COMMON_SOURCE_LOCATION_H_
+1 -1
View File
@@ -58,7 +58,7 @@ cc_binary(
":fuzzer_util",
"//common:error",
"//common/fuzzing:carbon_cc_proto",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:nonnull",
"//executable_semantics/syntax",
"@com_google_protobuf//:protobuf_headers",
+1 -1
View File
@@ -19,7 +19,7 @@
#include "common/error.h"
#include "common/fuzzing/carbon.pb.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "executable_semantics/fuzzing/ast_to_proto.h"
#include "executable_semantics/fuzzing/fuzzer_util.h"
#include "executable_semantics/syntax/parse.h"
+6 -6
View File
@@ -29,7 +29,7 @@ cc_library(
"//executable_semantics/ast:pattern",
"//executable_semantics/ast:statement",
"//executable_semantics/common:arena",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:nonnull",
"@llvm-project//llvm:Support",
],
@@ -105,9 +105,9 @@ cc_library(
":address",
":heap_allocation_interface",
"//common:ostream",
"//executable_semantics/ast:source_location",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:nonnull",
"//executable_semantics/common:source_location",
"@llvm-project//llvm:Support",
],
)
@@ -143,7 +143,7 @@ cc_library(
"//executable_semantics/ast:expression",
"//executable_semantics/ast:pattern",
"//executable_semantics/common:arena",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"@llvm-project//llvm:Support",
],
)
@@ -158,7 +158,7 @@ cc_library(
"//executable_semantics/ast:declaration",
"//executable_semantics/ast:return_term",
"//executable_semantics/ast:statement",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:nonnull",
"@llvm-project//llvm:Support",
],
@@ -208,7 +208,7 @@ cc_library(
"//executable_semantics/ast:expression",
"//executable_semantics/ast:statement",
"//executable_semantics/common:arena",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:nonnull",
"@llvm-project//llvm:Support",
],
@@ -77,7 +77,7 @@ auto ActionStack::ValueOfNode(ValueNodeView value_node,
}
}
// TODO: Move these errors to compile time and explain them more clearly.
return FATAL_RUNTIME_ERROR(source_loc)
return RuntimeError(source_loc)
<< "could not find `" << value_node.base() << "`";
}
+2 -2
View File
@@ -4,7 +4,7 @@
#include "executable_semantics/interpreter/heap.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Error.h"
@@ -40,7 +40,7 @@ auto Heap::Write(const Address& a, Nonnull<const Value*> v,
auto Heap::CheckAlive(AllocationId allocation, SourceLocation source_loc) const
-> ErrorOr<Success> {
if (!alive_[allocation.index_]) {
return FATAL_RUNTIME_ERROR(source_loc)
return RuntimeError(source_loc)
<< "undefined behavior: access to dead value "
<< *values_[allocation.index_];
}
+1 -1
View File
@@ -8,8 +8,8 @@
#include <vector>
#include "common/ostream.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/common/nonnull.h"
#include "executable_semantics/common/source_location.h"
#include "executable_semantics/interpreter/address.h"
#include "executable_semantics/interpreter/heap_allocation_interface.h"
#include "executable_semantics/interpreter/value.h"
@@ -4,7 +4,7 @@
#include "executable_semantics/interpreter/impl_scope.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "executable_semantics/interpreter/value.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
@@ -29,9 +29,8 @@ auto ImplScope::Resolve(Nonnull<const Value*> iface_type,
ASSIGN_OR_RETURN(std::optional<ValueNodeView> result,
TryResolve(iface_type, type, source_loc));
if (!result.has_value()) {
return FATAL_COMPILATION_ERROR(source_loc)
<< "could not find implementation of " << *iface_type << " for "
<< *type;
return CompilationError(source_loc) << "could not find implementation of "
<< *iface_type << " for " << *type;
}
return *result;
}
@@ -50,9 +49,8 @@ auto ImplScope::TryResolve(Nonnull<const Value*> iface_type,
parent->TryResolve(iface_type, type, source_loc));
if (parent_result.has_value() && result.has_value() &&
*parent_result != *result) {
return FATAL_COMPILATION_ERROR(source_loc)
<< "ambiguous implementations of " << *iface_type << " for "
<< *type;
return CompilationError(source_loc) << "ambiguous implementations of "
<< *iface_type << " for " << *type;
}
result = parent_result;
}
@@ -15,7 +15,7 @@
#include "executable_semantics/ast/declaration.h"
#include "executable_semantics/ast/expression.h"
#include "executable_semantics/common/arena.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "executable_semantics/interpreter/action.h"
#include "executable_semantics/interpreter/action_stack.h"
#include "executable_semantics/interpreter/stack.h"
@@ -560,7 +560,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
const auto& tuple = cast<TupleValue>(*act.results()[0]);
int i = cast<IntValue>(*act.results()[1]).value();
if (i < 0 || i >= static_cast<int>(tuple.elements().size())) {
return FATAL_RUNTIME_ERROR_NO_LINE()
return RuntimeError(exp.source_loc())
<< "index " << i << " out of range in " << tuple;
}
return todo_.FinishAction(tuple.elements()[i]);
@@ -813,7 +813,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
}
}
default:
return FATAL_RUNTIME_ERROR(exp.source_loc())
return RuntimeError(exp.source_loc())
<< "in call, expected a function, not " << *act.results()[0];
}
} else if (act.pos() == 3) {
@@ -7,7 +7,7 @@
#include "executable_semantics/ast/declaration.h"
#include "executable_semantics/ast/return_term.h"
#include "executable_semantics/ast/statement.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Error.h"
@@ -39,14 +39,14 @@ static auto ResolveControlFlow(Nonnull<Statement*> statement,
switch (statement->kind()) {
case StatementKind::Return: {
if (!function.has_value()) {
return FATAL_COMPILATION_ERROR(statement->source_loc())
return CompilationError(statement->source_loc())
<< "return is not within a function body";
}
const ReturnTerm& function_return =
(*function)->declaration->return_term();
if (function_return.is_auto()) {
if ((*function)->saw_return_in_auto) {
return FATAL_COMPILATION_ERROR(statement->source_loc())
return CompilationError(statement->source_loc())
<< "Only one return is allowed in a function with an `auto` "
"return type.";
}
@@ -55,7 +55,7 @@ static auto ResolveControlFlow(Nonnull<Statement*> statement,
auto& ret = cast<Return>(*statement);
ret.set_function((*function)->declaration);
if (ret.is_omitted_expression() != function_return.is_omitted()) {
return FATAL_COMPILATION_ERROR(ret.source_loc())
return CompilationError(ret.source_loc())
<< ret << " should"
<< (function_return.is_omitted() ? " not" : "")
<< " provide a return value, to match the function's signature.";
@@ -64,14 +64,14 @@ static auto ResolveControlFlow(Nonnull<Statement*> statement,
}
case StatementKind::Break:
if (!loop.has_value()) {
return FATAL_COMPILATION_ERROR(statement->source_loc())
return CompilationError(statement->source_loc())
<< "break is not within a loop body";
}
cast<Break>(*statement).set_loop(*loop);
return Success();
case StatementKind::Continue:
if (!loop.has_value()) {
return FATAL_COMPILATION_ERROR(statement->source_loc())
return CompilationError(statement->source_loc())
<< "continue is not within a loop body";
}
cast<Continue>(*statement).set_loop(*loop);
@@ -167,8 +167,7 @@ static auto ResolveNames(Expression& expression,
case ExpressionKind::TypeTypeLiteral:
break;
case ExpressionKind::UnimplementedExpression:
return FATAL_COMPILATION_ERROR(expression.source_loc())
<< "Unimplemented";
return CompilationError(expression.source_loc()) << "Unimplemented";
}
return Success();
}
@@ -376,7 +375,7 @@ static auto ResolveNames(Declaration& declaration, StaticScope& enclosing_scope)
RETURN_IF_ERROR(
ResolveNames(alternative->signature(), enclosing_scope));
if (!alternative_names.insert(alternative->name()).second) {
return FATAL_COMPILATION_ERROR(alternative->source_loc())
return CompilationError(alternative->source_loc())
<< "Duplicate name `" << alternative->name()
<< "` in choice type";
}
@@ -13,7 +13,7 @@
#include "common/ostream.h"
#include "executable_semantics/ast/declaration.h"
#include "executable_semantics/common/arena.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "executable_semantics/interpreter/impl_scope.h"
#include "executable_semantics/interpreter/interpreter.h"
#include "executable_semantics/interpreter/value.h"
@@ -42,10 +42,9 @@ static auto ExpectExactType(SourceLocation source_loc,
Nonnull<const Value*> expected,
Nonnull<const Value*> actual) -> ErrorOr<Success> {
if (!TypeEqual(expected, actual)) {
return FATAL_COMPILATION_ERROR(source_loc)
<< "type error in " << context << "\n"
<< "expected: " << *expected << "\n"
<< "actual: " << *actual;
return CompilationError(source_loc) << "type error in " << context << "\n"
<< "expected: " << *expected << "\n"
<< "actual: " << *actual;
}
return Success();
}
@@ -55,10 +54,9 @@ static auto ExpectPointerType(SourceLocation source_loc,
Nonnull<const Value*> actual)
-> ErrorOr<Success> {
if (actual->kind() != Value::Kind::PointerType) {
return FATAL_COMPILATION_ERROR(source_loc)
<< "type error in " << context << "\n"
<< "expected a pointer type\n"
<< "actual: " << *actual;
return CompilationError(source_loc) << "type error in " << context << "\n"
<< "expected a pointer type\n"
<< "actual: " << *actual;
}
return Success();
}
@@ -116,7 +114,7 @@ auto TypeChecker::ExpectIsConcreteType(SourceLocation source_loc,
Nonnull<const Value*> value)
-> ErrorOr<Success> {
if (!IsConcreteType(value)) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "Expected a type, but got " << *value;
} else {
return Success();
@@ -230,7 +228,7 @@ auto TypeChecker::ExpectType(SourceLocation source_loc,
Nonnull<const Value*> expected,
Nonnull<const Value*> actual) -> ErrorOr<Success> {
if (!IsImplicitlyConvertible(actual, expected)) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "type error in " << context << ": "
<< "'" << *actual << "' is not implicitly convertible to '"
<< *expected << "'";
@@ -257,7 +255,7 @@ auto TypeChecker::ArgumentDeduction(SourceLocation source_loc,
}
case Value::Kind::TupleValue: {
if (arg_type->kind() != Value::Kind::TupleValue) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "type error in argument deduction\n"
<< "expected: " << *param_type << "\n"
<< "actual: " << *arg_type;
@@ -265,7 +263,7 @@ auto TypeChecker::ArgumentDeduction(SourceLocation source_loc,
const auto& param_tup = cast<TupleValue>(*param_type);
const auto& arg_tup = cast<TupleValue>(*arg_type);
if (param_tup.elements().size() != arg_tup.elements().size()) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "mismatch in tuple sizes, expected "
<< param_tup.elements().size() << " but got "
<< arg_tup.elements().size();
@@ -279,7 +277,7 @@ auto TypeChecker::ArgumentDeduction(SourceLocation source_loc,
}
case Value::Kind::StructType: {
if (arg_type->kind() != Value::Kind::StructType) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "type error in argument deduction\n"
<< "expected: " << *param_type << "\n"
<< "actual: " << *arg_type;
@@ -287,14 +285,14 @@ auto TypeChecker::ArgumentDeduction(SourceLocation source_loc,
const auto& param_struct = cast<StructType>(*param_type);
const auto& arg_struct = cast<StructType>(*arg_type);
if (param_struct.fields().size() != arg_struct.fields().size()) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "mismatch in struct field counts, expected "
<< param_struct.fields().size() << " but got "
<< arg_struct.fields().size();
}
for (size_t i = 0; i < param_struct.fields().size(); ++i) {
if (param_struct.fields()[i].name != arg_struct.fields()[i].name) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "mismatch in field names, " << param_struct.fields()[i].name
<< " != " << arg_struct.fields()[i].name;
}
@@ -306,7 +304,7 @@ auto TypeChecker::ArgumentDeduction(SourceLocation source_loc,
}
case Value::Kind::FunctionType: {
if (arg_type->kind() != Value::Kind::FunctionType) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "type error in argument deduction\n"
<< "expected: " << *param_type << "\n"
<< "actual: " << *arg_type;
@@ -322,7 +320,7 @@ auto TypeChecker::ArgumentDeduction(SourceLocation source_loc,
}
case Value::Kind::PointerType: {
if (arg_type->kind() != Value::Kind::PointerType) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "type error in argument deduction\n"
<< "expected: " << *param_type << "\n"
<< "actual: " << *arg_type;
@@ -349,7 +347,7 @@ auto TypeChecker::ArgumentDeduction(SourceLocation source_loc,
return Success();
}
}
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "type error in argument deduction\n"
<< "expected: " << *param_type << "\n"
<< "actual: " << *arg_type;
@@ -497,7 +495,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
InterpExp(&index.offset(), arena_, trace_));
int i = cast<IntValue>(*offset_value).value();
if (i < 0 || i >= static_cast<int>(tuple_type.elements().size())) {
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "index " << i << " is out of range for type "
<< tuple_type;
}
@@ -515,7 +513,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
return Success();
}
default:
return FATAL_COMPILATION_ERROR(e->source_loc()) << "expected a tuple";
return CompilationError(e->source_loc()) << "expected a tuple";
}
}
case ExpressionKind::TupleLiteral: {
@@ -573,7 +571,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
return Success();
}
}
return FATAL_COMPILATION_ERROR(access.source_loc())
return CompilationError(access.source_loc())
<< "struct " << struct_type << " does not have a field named "
<< access.field();
}
@@ -599,7 +597,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
}
return Success();
} else {
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "class " << t_class.declaration().name()
<< " does not have a field named " << access.field();
}
@@ -610,7 +608,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
std::optional<Nonnull<const Value*>> parameter_types =
choice.FindAlternative(access.field());
if (!parameter_types.has_value()) {
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "choice " << choice.name()
<< " does not have a field named " << access.field();
}
@@ -641,10 +639,10 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
default:
break;
}
return FATAL_COMPILATION_ERROR(access.source_loc())
return CompilationError(access.source_loc())
<< access.field() << " is not a class function";
} else {
return FATAL_COMPILATION_ERROR(access.source_loc())
return CompilationError(access.source_loc())
<< class_type << " does not have a class function named "
<< access.field();
}
@@ -674,14 +672,14 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
access.set_impl(*var_type.binding().impl_binding());
return Success();
} else {
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "field access, " << access.field() << " not in "
<< iface_decl.name();
}
break;
}
default:
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "field access, unexpected " << aggregate_type
<< " of non-interface type " << typeof_var << " in " << *e;
}
@@ -708,14 +706,14 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
access.set_impl(*var_type.binding().impl_binding());
return Success();
} else {
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "field access, " << access.field() << " not in "
<< iface_decl.name();
}
break;
}
default:
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "field access, unexpected " << aggregate_type << " in "
<< *e;
}
@@ -728,7 +726,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
cast<FunctionDeclaration>(ident.value_node().base());
if (!function.has_static_type()) {
CHECK(function.return_term().is_auto());
return FATAL_COMPILATION_ERROR(ident.source_loc())
return CompilationError(ident.source_loc())
<< "Function calls itself, but has a deduced return type";
}
}
@@ -822,7 +820,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
return Success();
case Operator::AddressOf:
if (op.arguments()[0]->value_category() != ValueCategory::Var) {
return FATAL_COMPILATION_ERROR(op.arguments()[0]->source_loc())
return CompilationError(op.arguments()[0]->source_loc())
<< "Argument to " << ToString(op.op())
<< " should be an lvalue.";
}
@@ -853,7 +851,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
// has been added to the type checking of function signatures.
if (auto it = deduced_type_args.find(deduced_param);
it == deduced_type_args.end()) {
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "could not deduce type argument for type parameter "
<< deduced_param->name() << "\n"
<< "in " << call;
@@ -880,7 +878,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
case Value::Kind::TypeType:
break;
default:
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "unexpected type of deduced parameter "
<< *impl_binding->interface();
}
@@ -913,7 +911,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
CHECK(PatternMatch(&(*class_decl.type_params())->value(), arg,
call.source_loc(), std::nullopt, generic_args));
} else {
return FATAL_COMPILATION_ERROR(call.source_loc())
return CompilationError(call.source_loc())
<< "attempt to instantiate a non-generic class: " << *e;
}
// Find impls for all the impl bindings of the class.
@@ -934,7 +932,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
case Value::Kind::TypeType:
break;
default:
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "unexpected type of deduced parameter "
<< *impl_binding->interface();
}
@@ -948,7 +946,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
return Success();
}
default: {
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "in call, expected a function\n"
<< *e << "\nnot an operator of type "
<< call.function().static_type() << "\n";
@@ -980,7 +978,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
switch (cast<IntrinsicExpression>(*e).intrinsic()) {
case IntrinsicExpression::Intrinsic::Print:
if (intrinsic_exp.args().fields().size() != 1) {
return FATAL_COMPILATION_ERROR(e->source_loc())
return CompilationError(e->source_loc())
<< "__intrinsic_print takes 1 argument";
}
RETURN_IF_ERROR(
@@ -1040,8 +1038,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
Nonnull<const Value*> size_value,
InterpExp(&array_literal.size_expression(), arena_, trace_));
if (cast<IntValue>(size_value)->value() < 0) {
return FATAL_COMPILATION_ERROR(
array_literal.size_expression().source_loc())
return CompilationError(array_literal.size_expression().source_loc())
<< "Array size cannot be negative";
}
array_literal.set_static_type(arena_->New<TypeType>());
@@ -1107,7 +1104,7 @@ auto TypeChecker::TypeCheckPattern(
case PatternKind::BindingPattern: {
auto& binding = cast<BindingPattern>(*p);
if (!GetBindings(binding.type()).empty()) {
return FATAL_COMPILATION_ERROR(binding.type().source_loc())
return CompilationError(binding.type().source_loc())
<< "The type of a binding pattern cannot contain bindings.";
}
RETURN_IF_ERROR(TypeCheckPattern(&binding.type(), std::nullopt,
@@ -1122,7 +1119,7 @@ auto TypeChecker::TypeCheckPattern(
BindingMap generic_args;
if (!PatternMatch(type, *expected, binding.type().source_loc(),
std::nullopt, generic_args)) {
return FATAL_COMPILATION_ERROR(binding.type().source_loc())
return CompilationError(binding.type().source_loc())
<< "Type pattern '" << *type
<< "' does not match actual type '" << **expected << "'";
}
@@ -1146,7 +1143,7 @@ auto TypeChecker::TypeCheckPattern(
ASSIGN_OR_RETURN(Nonnull<const Value*> type,
InterpExp(&binding.type(), arena_, trace_));
if (expected) {
return FATAL_COMPILATION_ERROR(binding.type().source_loc())
return CompilationError(binding.type().source_loc())
<< "Generic binding may not occur in pattern with expected "
"type: "
<< binding;
@@ -1165,12 +1162,11 @@ auto TypeChecker::TypeCheckPattern(
auto& tuple = cast<TuplePattern>(*p);
std::vector<Nonnull<const Value*>> field_types;
if (expected && (*expected)->kind() != Value::Kind::TupleValue) {
return FATAL_COMPILATION_ERROR(p->source_loc())
<< "didn't expect a tuple";
return CompilationError(p->source_loc()) << "didn't expect a tuple";
}
if (expected && tuple.fields().size() !=
cast<TupleValue>(**expected).elements().size()) {
return FATAL_COMPILATION_ERROR(tuple.source_loc())
return CompilationError(tuple.source_loc())
<< "tuples of different length";
}
for (size_t i = 0; i < tuple.fields().size(); ++i) {
@@ -1197,7 +1193,7 @@ auto TypeChecker::TypeCheckPattern(
RETURN_IF_ERROR(TypeCheckExp(&alternative.choice_type(), impl_scope));
if (alternative.choice_type().static_type().kind() !=
Value::Kind::TypeOfChoiceType) {
return FATAL_COMPILATION_ERROR(alternative.source_loc())
return CompilationError(alternative.source_loc())
<< "alternative pattern does not name a choice type.";
}
if (expected) {
@@ -1212,7 +1208,7 @@ auto TypeChecker::TypeCheckPattern(
cast<ChoiceType>(choice_type)
.FindAlternative(alternative.alternative_name());
if (parameter_types == std::nullopt) {
return FATAL_COMPILATION_ERROR(alternative.source_loc())
return CompilationError(alternative.source_loc())
<< "'" << alternative.alternative_name()
<< "' is not an alternative of " << choice_type;
}
@@ -1302,7 +1298,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
&assign.lhs().static_type(),
&assign.rhs().static_type()));
if (assign.lhs().value_category() != ValueCategory::Var) {
return FATAL_COMPILATION_ERROR(assign.source_loc())
return CompilationError(assign.source_loc())
<< "Cannot assign to rvalue '" << assign.lhs() << "'";
}
return Success();
@@ -1377,7 +1373,7 @@ auto TypeChecker::ExpectReturnOnAllPaths(
std::optional<Nonnull<Statement*>> opt_stmt, SourceLocation source_loc)
-> ErrorOr<Success> {
if (!opt_stmt) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "control-flow reaches end of function that provides a `->` "
"return "
"type without reaching a return statement";
@@ -1387,7 +1383,7 @@ auto TypeChecker::ExpectReturnOnAllPaths(
case StatementKind::Match: {
auto& match = cast<Match>(*stmt);
if (!IsExhaustive(match)) {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "non-exhaustive match may allow control-flow to reach the "
"end "
"of a function that provides a `->` return type";
@@ -1402,7 +1398,7 @@ auto TypeChecker::ExpectReturnOnAllPaths(
case StatementKind::Block: {
auto& block = cast<Block>(*stmt);
if (block.statements().empty()) {
return FATAL_COMPILATION_ERROR(stmt->source_loc())
return CompilationError(stmt->source_loc())
<< "control-flow reaches end of function that provides a `->` "
"return type without reaching a return statement";
}
@@ -1431,7 +1427,7 @@ auto TypeChecker::ExpectReturnOnAllPaths(
case StatementKind::Break:
case StatementKind::Continue:
case StatementKind::VariableDefinition:
return FATAL_COMPILATION_ERROR(stmt->source_loc())
return CompilationError(stmt->source_loc())
<< "control-flow reaches end of function that provides a `->` "
"return type without reaching a return statement";
}
@@ -1497,7 +1493,7 @@ auto TypeChecker::DeclareFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
} else {
// We have to type-check the body in order to determine the return type.
if (!f->body().has_value()) {
return FATAL_COMPILATION_ERROR(f->return_term().source_loc())
return CompilationError(f->return_term().source_loc())
<< "Function declaration has deduced return type but no body";
}
RETURN_IF_ERROR(TypeCheckStmt(*f->body(), function_scope));
@@ -1515,7 +1511,7 @@ auto TypeChecker::DeclareFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
if (f->name() == "Main") {
if (!f->return_term().type_expression().has_value()) {
return FATAL_COMPILATION_ERROR(f->return_term().source_loc())
return CompilationError(f->return_term().source_loc())
<< "`Main` must have an explicit return type";
}
RETURN_IF_ERROR(ExpectExactType(
@@ -1696,7 +1692,7 @@ auto TypeChecker::DeclareImplDeclaration(Nonnull<ImplDeclaration*> impl_decl,
"member of implementation", iface_mem_type,
&(*mem)->static_type()));
} else {
return FATAL_COMPILATION_ERROR(impl_decl->source_loc())
return CompilationError(impl_decl->source_loc())
<< "implementation missing " << *mem_name;
}
}
@@ -1793,7 +1789,7 @@ auto TypeChecker::TypeCheckDeclaration(Nonnull<Declaration*> d,
dyn_cast<ExpressionPattern>(&var.binding().type());
if (binding_type == nullptr) {
// TODO: consider adding support for `auto`
return FATAL_COMPILATION_ERROR(var.source_loc())
return CompilationError(var.source_loc())
<< "Type of a top-level variable must be an expression.";
}
if (var.has_initializer()) {
@@ -1845,7 +1841,7 @@ auto TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d,
// Associate the variable name with it's declared type in the
// compile-time symbol table.
if (!llvm::isa<ExpressionPattern>(var.binding().type())) {
return FATAL_COMPILATION_ERROR(var.binding().type().source_loc())
return CompilationError(var.binding().type().source_loc())
<< "Expected expression for variable type";
}
Expression& type =
+10 -13
View File
@@ -8,7 +8,7 @@
#include "common/check.h"
#include "executable_semantics/common/arena.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "executable_semantics/interpreter/action.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
@@ -49,7 +49,7 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
return *fun_decl.constant_value();
}
} else {
return FATAL_COMPILATION_ERROR(source_loc)
return CompilationError(source_loc)
<< "member " << f << " not in " << *witness;
}
}
@@ -62,8 +62,7 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
std::optional<Nonnull<const Value*>> field =
cast<StructValue>(*v).FindField(f);
if (field == std::nullopt) {
return FATAL_RUNTIME_ERROR(source_loc)
<< "member " << f << " not in " << *v;
return RuntimeError(source_loc) << "member " << f << " not in " << *v;
}
return *field;
}
@@ -80,9 +79,8 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
std::optional<Nonnull<const FunctionValue*>> func =
class_type.FindFunction(f);
if (func == std::nullopt) {
return FATAL_RUNTIME_ERROR(source_loc)
<< "member " << f << " not in " << *v << " or its "
<< class_type;
return RuntimeError(source_loc) << "member " << f << " not in " << *v
<< " or its " << class_type;
} else if ((*func)->declaration().is_method()) {
// Found a method. Turn it into a bound method.
const FunctionValue& m = cast<FunctionValue>(**func);
@@ -101,7 +99,7 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
case Value::Kind::ChoiceType: {
const auto& choice = cast<ChoiceType>(*v);
if (!choice.FindAlternative(f)) {
return FATAL_RUNTIME_ERROR(source_loc)
return RuntimeError(source_loc)
<< "alternative " << f << " not in " << *v;
}
return arena->New<AlternativeConstructorValue>(f, choice.name());
@@ -112,7 +110,7 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
std::optional<Nonnull<const FunctionValue*>> fun =
class_type.FindFunction(f);
if (fun == std::nullopt) {
return FATAL_RUNTIME_ERROR(source_loc)
return RuntimeError(source_loc)
<< "class function " << f << " not in " << *v;
}
return arena->New<FunctionValue>(&(*fun)->declaration(),
@@ -151,7 +149,7 @@ static auto SetFieldImpl(
return element.name == (*path_begin).name();
});
if (it == elements.end()) {
return FATAL_RUNTIME_ERROR(source_loc)
return RuntimeError(source_loc)
<< "field " << (*path_begin).name() << " not in " << *value;
}
ASSIGN_OR_RETURN(it->value,
@@ -169,9 +167,8 @@ static auto SetFieldImpl(
// TODO(geoffromer): update FieldPath to hold integers as well as strings.
int index = std::stoi((*path_begin).name());
if (index < 0 || static_cast<size_t>(index) >= elements.size()) {
return FATAL_RUNTIME_ERROR(source_loc)
<< "index " << (*path_begin).name() << " out of range in "
<< *value;
return RuntimeError(source_loc) << "index " << (*path_begin).name()
<< " out of range in " << *value;
}
ASSIGN_OR_RETURN(elements[index],
SetFieldImpl(arena, elements[index], path_begin + 1,
+1 -1
View File
@@ -85,7 +85,7 @@ cc_library(
"//executable_semantics/ast:pattern",
"//executable_semantics/ast:value_category",
"//executable_semantics/common:arena",
"//executable_semantics/common:error",
"//executable_semantics/common:error_builders",
"//executable_semantics/common:nonnull",
"@llvm-project//llvm:Support",
],
+5 -4
View File
@@ -6,7 +6,7 @@
#include "common/check.h"
#include "common/error.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/error_builders.h"
#include "executable_semantics/syntax/lexer.h"
#include "executable_semantics/syntax/parse_and_lex_context.h"
#include "executable_semantics/syntax/parser.h"
@@ -41,10 +41,11 @@ auto ParseImpl(yyscan_t scanner, Nonnull<Arena*> arena,
auto Parse(Nonnull<Arena*> arena, std::string_view input_file_name, bool trace)
-> ErrorOr<AST> {
FILE* input_file = fopen(std::string(input_file_name).c_str(), "r");
std::string name_str(input_file_name);
FILE* input_file = fopen(name_str.c_str(), "r");
if (input_file == nullptr) {
return FATAL_PROGRAM_ERROR_NO_LINE() << "Error opening '" << input_file_name
<< "': " << std::strerror(errno);
return ProgramError(SourceLocation(name_str.c_str(), 0))
<< "Error opening file: " << std::strerror(errno);
}
// Prepare the lexer.
+1 -1
View File
@@ -7,7 +7,7 @@
// RUN: %{not} %{executable_semantics} --trace %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{executable_semantics} %s
// CHECK: RUNTIME ERROR: index 2 out of range in (0, 1)
// CHECK: RUNTIME ERROR: {{.*}}/executable_semantics/testdata/array/fail_index.carbon:16: index 2 out of range in (0, 1)
package ExecutableSemanticsTest api;