diff --git a/common/error.h b/common/error.h index 1752c242408e..bc0d27f21c1a 100644 --- a/common/error.h +++ b/common/error.h @@ -23,36 +23,27 @@ struct Success {}; class [[nodiscard]] Error { public: // Represents an error state. - explicit Error(llvm::Twine prefix, llvm::Twine location, llvm::Twine message) - : prefix_(prefix.str()), - location_(location.str()), - message_(message.str()) { + explicit Error(llvm::Twine location, llvm::Twine message) + : location_(location.str()), message_(message.str()) { CARBON_CHECK(!message_.empty()) << "Errors must have a message."; } - // Represents an error with no associated prefix or location. + // Represents an error with no associated location. // TODO: Consider using two different types. - explicit Error(llvm::Twine message) : Error("", "", message) {} + explicit Error(llvm::Twine message) : Error("", message) {} Error(Error&& other) noexcept - : prefix_(std::move(other.prefix_)), - location_(std::move(other.location_)), + : location_(std::move(other.location_)), message_(std::move(other.message_)) {} // Prints the error string. void Print(llvm::raw_ostream& out) const { - if (!prefix().empty()) { - out << prefix() << ": "; - } if (!location().empty()) { out << location() << ": "; } out << message(); } - // Returns the prefix to prepend to the error, such as "ERROR". - auto prefix() const -> const std::string& { return prefix_; } - // Returns a string describing the location of the error, such as // "file.cc:123". auto location() const -> const std::string& { return location_; } @@ -61,8 +52,6 @@ class [[nodiscard]] Error { auto message() const -> const std::string& { return message_; } private: - // A prefix, indicating the kind of error. - std::string prefix_; // The location associated with the error. std::string location_; // The error message. @@ -138,13 +127,10 @@ class [[nodiscard]] ErrorOr { // `Error` and `ErrorOr`. class ErrorBuilder { public: - explicit ErrorBuilder(std::string prefix, std::string location) - : prefix_(std::move(prefix)), - location_(std::move(location)), + explicit ErrorBuilder(std::string location = "") + : location_(std::move(location)), out_(std::make_unique(message_)) {} - explicit ErrorBuilder() : ErrorBuilder("", "") {} - // Accumulates string message. template [[nodiscard]] auto operator<<(const T& message) -> ErrorBuilder& { @@ -153,16 +139,15 @@ class ErrorBuilder { } // NOLINTNEXTLINE(google-explicit-constructor): Implicit cast for returns. - operator Error() { return Error(prefix_, location_, message_); } + operator Error() { return Error(location_, message_); } template // NOLINTNEXTLINE(google-explicit-constructor): Implicit cast for returns. operator ErrorOr() { - return Error(prefix_, location_, message_); + return Error(location_, message_); } private: - std::string prefix_; std::string location_; std::string message_; // Use a pointer to allow move construction. diff --git a/explorer/ast/declaration.cpp b/explorer/ast/declaration.cpp index a0c27c9af8ba..3ae2f90c2601 100644 --- a/explorer/ast/declaration.cpp +++ b/explorer/ast/declaration.cpp @@ -262,11 +262,11 @@ auto SplitDeducedParameters( case AstNodeKind::BindingPattern: { Nonnull binding = &cast(*param); if (binding->name() != "me") { - return CompilationError(source_loc) + return ProgramError(source_loc) << "illegal binding pattern in implicit parameter list"; } if (result.me_pattern.has_value()) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "parameter list cannot contain more than one `me` " "parameter"; } @@ -278,11 +278,11 @@ auto SplitDeducedParameters( Nonnull binding = &cast(addr_pattern->binding()); if (binding->name() != "me") { - return CompilationError(source_loc) + return ProgramError(source_loc) << "illegal binding pattern in implicit parameter list"; } if (result.me_pattern.has_value()) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "parameter list cannot contain more than one `me` " "parameter"; } @@ -290,7 +290,7 @@ auto SplitDeducedParameters( break; } default: - return CompilationError(source_loc) + return ProgramError(source_loc) << "illegal AST node in implicit parameter list"; } } @@ -360,7 +360,7 @@ auto ImplDeclaration::Create(Nonnull arena, SourceLocation source_loc, resolved_params.push_back(&cast(*param)); break; default: - return CompilationError(source_loc) + return ProgramError(source_loc) << "illegal AST node in implicit parameter list of impl"; } } diff --git a/explorer/ast/expression.cpp b/explorer/ast/expression.cpp index 43ff49a6622d..37aa80e48110 100644 --- a/explorer/ast/expression.cpp +++ b/explorer/ast/expression.cpp @@ -45,7 +45,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 CompilationError(source_loc) << "Unknown intrinsic '" << name << "'"; + return ProgramError(source_loc) << "Unknown intrinsic '" << name << "'"; } return it->second; } diff --git a/explorer/ast/static_scope.cpp b/explorer/ast/static_scope.cpp index 26b249229334..19e55392a2c5 100644 --- a/explorer/ast/static_scope.cpp +++ b/explorer/ast/static_scope.cpp @@ -17,7 +17,7 @@ auto StaticScope::Add(const std::string& name, ValueNodeView entity, auto [it, inserted] = declared_names_.insert({name, {entity, status}}); if (!inserted) { if (it->second.entity != entity) { - return CompilationError(entity.base().source_loc()) + return ProgramError(entity.base().source_loc()) << "Duplicate name `" << name << "` also found at " << it->second.entity.base().source_loc(); } @@ -48,7 +48,7 @@ auto StaticScope::Resolve(const std::string& name, CARBON_ASSIGN_OR_RETURN(std::optional result, TryResolve(name, source_loc)); if (!result) { - return CompilationError(source_loc) << "could not resolve '" << name << "'"; + return ProgramError(source_loc) << "could not resolve '" << name << "'"; } return *result; } @@ -60,10 +60,10 @@ auto StaticScope::TryResolve(const std::string& name, if (it != declared_names_.end()) { switch (it->second.status) { case NameStatus::KnownButNotDeclared: - return CompilationError(source_loc) + return ProgramError(source_loc) << "'" << name << "' has not been declared yet"; case NameStatus::DeclaredButNotUsable: - return CompilationError(source_loc) + return ProgramError(source_loc) << "'" << name << "' is not usable until after it has been completely declared"; case NameStatus::Usable: @@ -76,7 +76,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 CompilationError(source_loc) + return ProgramError(source_loc) << "'" << name << "' is ambiguous between " << result->base().source_loc() << " and " << parent_result->base().source_loc(); @@ -90,7 +90,7 @@ auto StaticScope::AddReturnedVar(ValueNodeView returned_var_def_view) -> ErrorOr { std::optional resolved_returned_var = ResolveReturned(); if (resolved_returned_var.has_value()) { - return CompilationError(returned_var_def_view.base().source_loc()) + return ProgramError(returned_var_def_view.base().source_loc()) << "Duplicate definition of returned var also found at " << resolved_returned_var->base().source_loc(); } diff --git a/explorer/common/error_builders.h b/explorer/common/error_builders.h index 9a31f098ee82..fde2444e935d 100644 --- a/explorer/common/error_builders.h +++ b/explorer/common/error_builders.h @@ -21,16 +21,8 @@ namespace Carbon { // 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 { - return ErrorBuilder("COMPILATION ERROR", loc.ToString()); -} - inline auto ProgramError(SourceLocation loc) -> ErrorBuilder { - return ErrorBuilder("PROGRAM ERROR", loc.ToString()); -} - -inline auto RuntimeError(SourceLocation loc) -> ErrorBuilder { - return ErrorBuilder("RUNTIME ERROR", loc.ToString()); + return ErrorBuilder(loc.ToString()); } } // namespace Carbon diff --git a/explorer/common/error_builders_test.cpp b/explorer/common/error_builders_test.cpp index a404f65248b1..4cf285543fad 100644 --- a/explorer/common/error_builders_test.cpp +++ b/explorer/common/error_builders_test.cpp @@ -18,28 +18,11 @@ auto ToString(const Error& err) -> std::string { return result; } -TEST(ErrorBuildersTest, CompilationError) { - Error err = CompilationError(SourceLocation("x", 1)) << "test"; - EXPECT_EQ(err.prefix(), "COMPILATION ERROR"); - EXPECT_EQ(err.location(), "x:1"); - EXPECT_EQ(err.message(), "test"); - EXPECT_EQ(ToString(err), "COMPILATION ERROR: x:1: test"); -} - TEST(ErrorBuildersTest, ProgramError) { Error err = ProgramError(SourceLocation("x", 1)) << "test"; - EXPECT_EQ(err.prefix(), "PROGRAM ERROR"); EXPECT_EQ(err.location(), "x:1"); EXPECT_EQ(err.message(), "test"); - EXPECT_EQ(ToString(err), "PROGRAM ERROR: x:1: test"); -} - -TEST(ErrorBuildersTest, RuntimeError) { - Error err = RuntimeError(SourceLocation("x", 1)) << "test"; - EXPECT_EQ(err.prefix(), "RUNTIME ERROR"); - EXPECT_EQ(err.location(), "x:1"); - EXPECT_EQ(err.message(), "test"); - EXPECT_EQ(ToString(err), "RUNTIME ERROR: x:1: test"); + EXPECT_EQ(ToString(err), "x:1: test"); } } // namespace diff --git a/explorer/fuzzing/fuzzer_util.cpp b/explorer/fuzzing/fuzzer_util.cpp index 64a13e2a3703..0fb85c7f6bf4 100644 --- a/explorer/fuzzing/fuzzer_util.cpp +++ b/explorer/fuzzing/fuzzer_util.cpp @@ -83,6 +83,8 @@ auto ParseAndExecute(const Fuzzing::CompilationUnit& compilation_unit) CARBON_CHECK(prelude_path.ok()) << prelude_path.error(); AddPrelude(*prelude_path, &arena, &ast.declarations); + CARBON_ASSIGN_OR_RETURN( + ast, AnalyzeProgram(&arena, ast, /*trace_stream=*/std::nullopt)); return ExecProgram(&arena, ast, /*trace_stream=*/std::nullopt); } diff --git a/explorer/interpreter/action_stack.cpp b/explorer/interpreter/action_stack.cpp index 605121d7cdf0..a6fb07720ff3 100644 --- a/explorer/interpreter/action_stack.cpp +++ b/explorer/interpreter/action_stack.cpp @@ -91,7 +91,7 @@ auto ActionStack::ValueOfNode(ValueNodeView value_node, } } // TODO: Move these errors to compile time and explain them more clearly. - return RuntimeError(source_loc) + return ProgramError(source_loc) << "could not find `" << value_node.base() << "`"; } diff --git a/explorer/interpreter/builtins.cpp b/explorer/interpreter/builtins.cpp index 0b343730ce00..1cdd2fa0576b 100644 --- a/explorer/interpreter/builtins.cpp +++ b/explorer/interpreter/builtins.cpp @@ -32,7 +32,7 @@ auto Builtins::Get(SourceLocation source_loc, Builtin builtin) const std::optional result = builtins_[static_cast(builtin)]; if (!result.has_value()) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "missing declaration for builtin `" << GetName(builtin) << "`"; } return result.value(); diff --git a/explorer/interpreter/exec_program.cpp b/explorer/interpreter/exec_program.cpp index 60b08af121d6..061154d48b1c 100644 --- a/explorer/interpreter/exec_program.cpp +++ b/explorer/interpreter/exec_program.cpp @@ -18,9 +18,9 @@ namespace Carbon { -auto ExecProgram(Nonnull arena, AST ast, - std::optional> trace_stream) - -> ErrorOr { +auto AnalyzeProgram(Nonnull arena, AST ast, + std::optional> trace_stream) + -> ErrorOr { if (trace_stream) { **trace_stream << "********** source program **********\n"; for (const auto decl : ast.declarations) { @@ -54,6 +54,14 @@ auto ExecProgram(Nonnull arena, AST ast, for (const auto decl : ast.declarations) { **trace_stream << *decl; } + } + return ast; +} + +auto ExecProgram(Nonnull arena, AST ast, + std::optional> trace_stream) + -> ErrorOr { + if (trace_stream) { **trace_stream << "********** starting execution **********\n"; } return InterpProgram(ast, arena, trace_stream); diff --git a/explorer/interpreter/exec_program.h b/explorer/interpreter/exec_program.h index 79d6d7b0e2d6..84619f1d8e33 100644 --- a/explorer/interpreter/exec_program.h +++ b/explorer/interpreter/exec_program.h @@ -14,7 +14,12 @@ namespace Carbon { -// Runs the top-level declaration list. +// Perform semantic analysis on the AST. +auto AnalyzeProgram(Nonnull arena, AST ast, + std::optional> trace_stream) + -> ErrorOr; + +// Run the program's `Main` function. auto ExecProgram(Nonnull arena, AST ast, std::optional> trace_stream) -> ErrorOr; diff --git a/explorer/interpreter/heap.cpp b/explorer/interpreter/heap.cpp index 46aa19c077dc..88f576822a71 100644 --- a/explorer/interpreter/heap.cpp +++ b/explorer/interpreter/heap.cpp @@ -49,7 +49,7 @@ auto Heap::Write(const Address& a, Nonnull v, auto Heap::CheckAlive(AllocationId allocation, SourceLocation source_loc) const -> ErrorOr { if (states_[allocation.index_] == ValueState::Dead) { - return RuntimeError(source_loc) + return ProgramError(source_loc) << "undefined behavior: access to dead value " << *values_[allocation.index_]; } @@ -59,7 +59,7 @@ auto Heap::CheckAlive(AllocationId allocation, SourceLocation source_loc) const auto Heap::CheckInit(AllocationId allocation, SourceLocation source_loc) const -> ErrorOr { if (states_[allocation.index_] == ValueState::Uninitialized) { - return RuntimeError(source_loc) + return ProgramError(source_loc) << "undefined behavior: access to uninitialized value " << *values_[allocation.index_]; } diff --git a/explorer/interpreter/impl_scope.cpp b/explorer/interpreter/impl_scope.cpp index ae6ff6656399..7b4847286d03 100644 --- a/explorer/interpreter/impl_scope.cpp +++ b/explorer/interpreter/impl_scope.cpp @@ -111,8 +111,8 @@ auto ImplScope::ResolveInterface(Nonnull iface_type, 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 ProgramError(source_loc) << "could not find implementation of " + << *iface_type << " for " << *type; } return *result; } @@ -133,8 +133,8 @@ auto ImplScope::TryResolve(Nonnull iface_type, type_checker)); if (parent_result.has_value()) { if (result.has_value()) { - return CompilationError(source_loc) << "ambiguous implementations of " - << *iface_type << " for " << *type; + return ProgramError(source_loc) << "ambiguous implementations of " + << *iface_type << " for " << *type; } else { result = *parent_result; } @@ -155,9 +155,8 @@ auto ImplScope::ResolveHere(Nonnull iface_type, *iface_type, 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; + return ProgramError(source_loc) << "ambiguous implementations of " + << *iface_type << " for " << *impl_type; } else { result = *m; } diff --git a/explorer/interpreter/interpreter.cpp b/explorer/interpreter/interpreter.cpp index 562e66f62122..d33e0f12c71f 100644 --- a/explorer/interpreter/interpreter.cpp +++ b/explorer/interpreter/interpreter.cpp @@ -533,7 +533,7 @@ auto Interpreter::EvalAssociatedConstant( if (!isa(witness)) { CARBON_CHECK(phase() == Phase::CompileTime) << "symbolic witnesses should only be formed at compile time"; - return CompilationError(source_loc) + return ProgramError(source_loc) << "value of associated constant " << *assoc << " is not known"; } @@ -893,7 +893,7 @@ auto Interpreter::CallFunction(const CallExpression& call, } } default: - return RuntimeError(call.source_loc()) + return ProgramError(call.source_loc()) << "in call, expected a function, not " << *fun; } } @@ -921,7 +921,7 @@ auto Interpreter::StepExp() -> ErrorOr { const auto& tuple = cast(*act.results()[0]); int i = cast(*act.results()[1]).value(); if (i < 0 || i >= static_cast(tuple.elements().size())) { - return RuntimeError(exp.source_loc()) + return ProgramError(exp.source_loc()) << "index " << i << " out of range in " << tuple; } return todo_.FinishAction(tuple.elements()[i]); @@ -1228,7 +1228,7 @@ auto Interpreter::StepExp() -> ErrorOr { Nonnull string_value, Convert(args[1], arena_->New(), exp.source_loc())); if (cast(condition)->value() == false) { - return RuntimeError(exp.source_loc()) << *string_value; + return ProgramError(exp.source_loc()) << *string_value; } return todo_.FinishAction(TupleValue::Empty()); } diff --git a/explorer/interpreter/resolve_control_flow.cpp b/explorer/interpreter/resolve_control_flow.cpp index 98dfad86f4e7..6ac0dd21a60b 100644 --- a/explorer/interpreter/resolve_control_flow.cpp +++ b/explorer/interpreter/resolve_control_flow.cpp @@ -40,14 +40,14 @@ static auto ResolveControlFlow(Nonnull statement, case StatementKind::ReturnVar: case StatementKind::ReturnExpression: { if (!function.has_value()) { - return CompilationError(statement->source_loc()) + return ProgramError(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 CompilationError(statement->source_loc()) + return ProgramError(statement->source_loc()) << "Only one return is allowed in a function with an `auto` " "return type."; } @@ -57,7 +57,7 @@ static auto ResolveControlFlow(Nonnull statement, ret.set_function((*function)->declaration); if (statement->kind() == StatementKind::ReturnVar && function_return.is_omitted()) { - return CompilationError(statement->source_loc()) + return ProgramError(statement->source_loc()) << *statement << " should not provide a return value, to match the function's " "signature."; @@ -65,7 +65,7 @@ static auto ResolveControlFlow(Nonnull statement, if (statement->kind() == StatementKind::ReturnExpression) { auto& ret_exp = cast(*statement); if (ret_exp.is_omitted_expression() != function_return.is_omitted()) { - return CompilationError(ret_exp.source_loc()) + return ProgramError(ret_exp.source_loc()) << ret_exp << " should" << (function_return.is_omitted() ? " not" : "") << " provide a return value, to match the function's " @@ -77,14 +77,14 @@ static auto ResolveControlFlow(Nonnull statement, } case StatementKind::Break: if (!loop.has_value()) { - return CompilationError(statement->source_loc()) + return ProgramError(statement->source_loc()) << "break is not within a loop body"; } cast(*statement).set_loop(*loop); return Success(); case StatementKind::Continue: if (!loop.has_value()) { - return CompilationError(statement->source_loc()) + return ProgramError(statement->source_loc()) << "continue is not within a loop body"; } cast(*statement).set_loop(*loop); diff --git a/explorer/interpreter/resolve_names.cpp b/explorer/interpreter/resolve_names.cpp index 53e86d41a7e1..0abe7d1f2c89 100644 --- a/explorer/interpreter/resolve_names.cpp +++ b/explorer/interpreter/resolve_names.cpp @@ -268,7 +268,7 @@ static auto ResolveNames(Expression& expression, case ExpressionKind::ValueLiteral: break; case ExpressionKind::UnimplementedExpression: - return CompilationError(expression.source_loc()) << "Unimplemented"; + return ProgramError(expression.source_loc()) << "Unimplemented"; } return Success(); } @@ -395,7 +395,7 @@ static auto ResolveNames(Statement& statement, StaticScope& enclosing_scope) std::optional returned_var_def_view = enclosing_scope.ResolveReturned(); if (!returned_var_def_view.has_value()) { - return CompilationError(ret_var_stmt.source_loc()) + return ProgramError(ret_var_stmt.source_loc()) << "`return var` is not allowed without a returned var defined " "in scope."; } @@ -407,7 +407,7 @@ static auto ResolveNames(Statement& statement, StaticScope& enclosing_scope) std::optional returned_var_def_view = enclosing_scope.ResolveReturned(); if (returned_var_def_view.has_value()) { - return CompilationError(ret_exp_stmt.source_loc()) + return ProgramError(ret_exp_stmt.source_loc()) << "`return ` is not allowed with a returned var " "defined in scope: " << returned_var_def_view->base().source_loc(); @@ -619,7 +619,7 @@ static auto ResolveNames(Declaration& declaration, StaticScope& enclosing_scope, CARBON_RETURN_IF_ERROR( ResolveNames(alternative->signature(), choice_scope)); if (!alternative_names.insert(alternative->name()).second) { - return CompilationError(alternative->source_loc()) + return ProgramError(alternative->source_loc()) << "Duplicate name `" << alternative->name() << "` in choice type"; } diff --git a/explorer/interpreter/resolve_unformed.cpp b/explorer/interpreter/resolve_unformed.cpp index 5c7878208abf..91ba69e41442 100644 --- a/explorer/interpreter/resolve_unformed.cpp +++ b/explorer/interpreter/resolve_unformed.cpp @@ -43,7 +43,7 @@ auto FlowFacts::TakeAction(Nonnull node, ActionType action, auto entry = facts_.find(node); if (entry != facts_.end() && entry->second.formed_state == FormedState::Unformed) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "use of uninitialized variable " << name; } break; diff --git a/explorer/interpreter/type_checker.cpp b/explorer/interpreter/type_checker.cpp index e73d3f020718..102c1bdb4ee4 100644 --- a/explorer/interpreter/type_checker.cpp +++ b/explorer/interpreter/type_checker.cpp @@ -55,9 +55,8 @@ struct TypeChecker::SingleStepEqualityContext : public EqualityContext { if (impl_witness) { return impl_witness; } - return CompilationError(source_loc) - << "value of associated constant " << *assoc - << " depends on a generic parameter"; + return ProgramError(source_loc) << "value of associated constant " << *assoc + << " depends on a generic parameter"; } // Visits the values that are equal to the given value and a single step away @@ -139,9 +138,9 @@ auto TypeChecker::ExpectExactType(SourceLocation source_loc, const ImplScope& impl_scope) const -> ErrorOr { if (!IsSameType(expected, actual, impl_scope)) { - return CompilationError(source_loc) << "type error in " << context << "\n" - << "expected: " << *expected << "\n" - << "actual: " << *actual; + return ProgramError(source_loc) << "type error in " << context << "\n" + << "expected: " << *expected << "\n" + << "actual: " << *actual; } return Success(); } @@ -152,9 +151,9 @@ static auto ExpectPointerType(SourceLocation source_loc, -> ErrorOr { // TODO: Try to resolve in equality context. if (actual->kind() != Value::Kind::PointerType) { - return CompilationError(source_loc) << "type error in " << context << "\n" - << "expected a pointer type\n" - << "actual: " << *actual; + return ProgramError(source_loc) << "type error in " << context << "\n" + << "expected a pointer type\n" + << "actual: " << *actual; } return Success(); } @@ -307,8 +306,7 @@ auto TypeChecker::ExpectIsType(SourceLocation source_loc, Nonnull value) -> ErrorOr { if (!IsType(value)) { - return CompilationError(source_loc) - << "Expected a type, but got " << *value; + return ProgramError(source_loc) << "Expected a type, but got " << *value; } else { return Success(); } @@ -324,8 +322,7 @@ auto TypeChecker::ExpectIsConcreteType(SourceLocation source_loc, Nonnull value) -> ErrorOr { if (!IsConcreteType(value)) { - return CompilationError(source_loc) - << "Expected a type, but got " << *value; + return ProgramError(source_loc) << "Expected a type, but got " << *value; } else { return Success(); } @@ -543,7 +540,7 @@ auto TypeChecker::ImplicitlyConvert(const std::string& context, BuiltinMethodCall{"Convert"}); if (!converted.ok()) { // We couldn't find a matching `impl`. - return CompilationError(source->source_loc()) + return ProgramError(source->source_loc()) << "type error in " << context << ": " << "'" << *source_type << "' is not implicitly convertible to '" << *destination << "'"; @@ -555,7 +552,7 @@ auto TypeChecker::GetBuiltinInterfaceType(SourceLocation source_loc, BuiltinInterfaceName interface) const -> ErrorOr> { auto bad_builtin = [&]() -> Error { - return CompilationError(source_loc) + return ProgramError(source_loc) << "unsupported declaration for builtin `" << Builtins::GetName(interface.builtin) << "`"; }; @@ -623,7 +620,7 @@ auto TypeChecker::ExpectType(SourceLocation source_loc, -> ErrorOr { if (!IsImplicitlyConvertible(actual, expected, impl_scope, /*allow_user_defined_conversions=*/true)) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "type error in " << context << ": " << "'" << *actual << "' is not implicitly convertible to '" << *expected << "'"; @@ -656,9 +653,9 @@ auto TypeChecker::ArgumentDeduction( // Parameter type contains a nested `auto` and argument type isn't the // same kind of type. // TODO: This seems like something we should be able to accept. - return CompilationError(source_loc) << "type error in " << context << "\n" - << "expected: " << *param << "\n" - << "actual: " << *arg; + return ProgramError(source_loc) << "type error in " << context << "\n" + << "expected: " << *param << "\n" + << "actual: " << *arg; } const Value* subst_param_type = Substitute(deduced, param); return allow_implicit_conversion @@ -676,7 +673,7 @@ auto TypeChecker::ArgumentDeduction( const Value* binding_type = Substitute(deduced, &binding.static_type()); if (!IsTypeOfType(binding_type)) { if (!IsImplicitlyConvertible(arg, binding_type, impl_scope, false)) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "cannot convert deduced value " << *arg << " for " << binding.name() << " to parameter type " << *binding_type; } @@ -693,7 +690,7 @@ auto TypeChecker::ArgumentDeduction( // should be used, and we'd need to check all pairs of types for // equality because our notion of equality is non-transitive. if (!TypeEqual(it->second, arg, std::nullopt)) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "deduced multiple different values for " << var_type.binding() << ":\n " << *it->second << "\n " << *arg; @@ -711,7 +708,7 @@ auto TypeChecker::ArgumentDeduction( const auto& param_tup = cast(*param); const auto& arg_tup = cast(*arg); if (param_tup.elements().size() != arg_tup.elements().size()) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "mismatch in tuple sizes, expected " << param_tup.elements().size() << " but got " << arg_tup.elements().size(); @@ -735,7 +732,7 @@ auto TypeChecker::ArgumentDeduction( bool missing_from_source) -> Error { static constexpr const char* SourceOrDestination[2] = {"source", "destination"}; - return CompilationError(source_loc) + return ProgramError(source_loc) << "mismatch in field names, " << SourceOrDestination[missing_from_source ? 1 : 0] << " field `" << field.name << "` not in " @@ -758,7 +755,7 @@ auto TypeChecker::ArgumentDeduction( } arg_field = arg_struct.fields()[i]; if (param_field.name != arg_field.name) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "mismatch in field names, `" << param_field.name << "` != `" << arg_field.name << "`"; } @@ -894,9 +891,8 @@ auto TypeChecker::ArgumentDeduction( // TODO: Deduce within the values where possible. // TODO: Consider in-scope value equalities here. if (!ValueEqual(param, arg, std::nullopt)) { - return CompilationError(source_loc) - << "mismatch in non-type values, `" << *arg << "` != `" << *param - << "`"; + return ProgramError(source_loc) << "mismatch in non-type values, `" + << *arg << "` != `" << *param << "`"; } return Success(); } @@ -1352,7 +1348,7 @@ auto TypeChecker::DeduceCallBindings( llvm::ArrayRef> args = cast(call.argument()).fields(); if (params.size() != args.size()) { - return CompilationError(call.source_loc()) + return ProgramError(call.source_loc()) << "wrong number of arguments in function call, expected " << params.size() << " but got " << args.size(); } @@ -1393,7 +1389,7 @@ auto TypeChecker::DeduceCallBindings( // has been added to the type checking of function signatures. if (auto it = generic_bindings.find(deduced_param); it == generic_bindings.end()) { - return CompilationError(call.source_loc()) + return ProgramError(call.source_loc()) << "could not deduce type argument for type parameter " << deduced_param->name() << "\n" << "in " << call; @@ -1466,7 +1462,7 @@ static auto LookupInConstraint(SourceLocation source_loc, } // TODO: If we resolve to the same member either way, this // is not ambiguous. - return CompilationError(source_loc) + return ProgramError(source_loc) << "ambiguous " << lookup_kind << ", " << member_name << " found in " << *found->interface << " and " << iface_type; } @@ -1476,10 +1472,10 @@ static auto LookupInConstraint(SourceLocation source_loc, if (!found) { if (isa(type)) { - return CompilationError(source_loc) + return ProgramError(source_loc) << lookup_kind << " in unconstrained type"; } - return CompilationError(source_loc) + return ProgramError(source_loc) << lookup_kind << ", " << member_name << " not in " << *type; } return found.value(); @@ -1520,7 +1516,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, InterpExp(&index.offset(), arena_, trace_stream_)); int i = cast(*offset_value).value(); if (i < 0 || i >= static_cast(tuple_type.elements().size())) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "index " << i << " is out of range for type " << tuple_type; } @@ -1539,7 +1535,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, return Success(); } default: - return CompilationError(e->source_loc()) << "expected a tuple"; + return ProgramError(e->source_loc()) << "expected a tuple"; } } case ExpressionKind::TupleLiteral: { @@ -1598,7 +1594,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, return Success(); } } - return CompilationError(access.source_loc()) + return ProgramError(access.source_loc()) << "struct " << struct_type << " does not have a field named " << access.member_name(); } @@ -1629,7 +1625,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, e->source_loc(), "method access, receiver type", me_type, &access.object().static_type(), impl_scope)); if (access.object().value_category() != ValueCategory::Var) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "method " << access.member_name() << " requires its receiver to be an lvalue"; } @@ -1644,7 +1640,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } return Success(); } else { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "class " << t_class.declaration().name() << " does not have a field named " << access.member_name(); } @@ -1759,7 +1755,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, return Success(); } } - return CompilationError(access.source_loc()) + return ProgramError(access.source_loc()) << "struct " << *type << " does not have a field named " << " does not have a field named " << access.member_name(); } @@ -1768,7 +1764,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, std::optional> parameter_types = choice.FindAlternative(access.member_name()); if (!parameter_types.has_value()) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "choice " << choice.name() << " does not have an alternative named " << access.member_name(); @@ -1819,7 +1815,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, access.set_value_category(ValueCategory::Let); return Success(); } else { - return CompilationError(access.source_loc()) + return ProgramError(access.source_loc()) << class_type << " does not have a member named " << access.member_name(); } @@ -1838,12 +1834,12 @@ auto TypeChecker::TypeCheckExp(Nonnull e, return Success(); } default: - return CompilationError(access.source_loc()) + return ProgramError(access.source_loc()) << "unsupported member access into type " << *type; } } default: - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "member access, unexpected " << object_type << " in " << *e; } } @@ -1852,7 +1848,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, CARBON_RETURN_IF_ERROR(TypeCheckExp(&access.object(), impl_scope)); CARBON_RETURN_IF_ERROR(TypeCheckExp(&access.path(), impl_scope)); if (!isa(access.path().static_type())) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "expected name of instance member or interface member in " "compound member access, found " << access.path().static_type(); @@ -1961,7 +1957,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, cast(ident.value_node().base()); if (!function.has_static_type()) { CARBON_CHECK(function.return_term().is_auto()); - return CompilationError(ident.source_loc()) + return ProgramError(ident.source_loc()) << "Function calls itself, but has a deduced return type"; } } @@ -2003,7 +1999,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, BuiltinMethodCall{"Op"}); if (!result.ok()) { // We couldn't find a matching `impl`. - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "type error in `" << ToString(op.op()) << "`:\n" << result.error().message(); } @@ -2018,7 +2014,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, BuiltinMethodCall{"Op", {op.arguments()[1]}}); if (!result.ok()) { // We couldn't find a matching `impl`. - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "type error in `" << ToString(op.op()) << "`:\n" << result.error().message(); } @@ -2049,7 +2045,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, BuiltinMethodCall{method_name, op.arguments()[1]}); if (!converted.ok()) { // We couldn't find a matching `impl`. - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << *ts[0] << " is not " << operator_desc << " comparable with " << *ts[1] << " (" << converted.error().message() << ")"; } @@ -2093,7 +2089,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, dyn_cast(ts[i])) { constraints[i] = &constraint_type_type->constraint_type(); } else { - return CompilationError(op.arguments()[i]->source_loc()) + return ProgramError(op.arguments()[i]->source_loc()) << "argument to " << ToString(op.op()) << " should be a constraint, found `" << *ts[i] << "`"; } @@ -2170,7 +2166,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, return Success(); case Operator::AddressOf: if (op.arguments()[0]->value_category() != ValueCategory::Var) { - return CompilationError(op.arguments()[0]->source_loc()) + return ProgramError(op.arguments()[0]->source_loc()) << "Argument to " << ToString(op.op()) << " should be an lvalue."; } @@ -2189,7 +2185,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, BuiltinMethodCall{"Convert"}); if (!converted.ok()) { // We couldn't find a matching `impl`. - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "type error in `as`: `" << *ts[0] << "` is not explicitly convertible to `" << *type << "`:\n" << converted.error().message(); @@ -2292,7 +2288,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } case Value::Kind::TypeOfChoiceType: default: { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "in call `" << *e << "`, expected callee to be a function, found `" << call.function().static_type() << "`"; @@ -2322,7 +2318,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, // overloads. Here, that's the name Print instead of __intrinsic_print // in errors. if (args.size() < 1 || args.size() > 2) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "Print takes 1 or 2 arguments, received " << args.size(); } CARBON_RETURN_IF_ERROR(ExpectExactType( @@ -2338,7 +2334,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, return Success(); case IntrinsicExpression::Intrinsic::Assert: { if (args.size() != 2) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "__intrinsic_assert takes 2 arguments"; } CARBON_RETURN_IF_ERROR(ExpectType( @@ -2353,7 +2349,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } case IntrinsicExpression::Intrinsic::Alloc: { if (args.size() != 1) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "__intrinsic_new takes 1 argument"; } auto arg_type = &args[0]->static_type(); @@ -2363,7 +2359,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } case IntrinsicExpression::Intrinsic::Dealloc: { if (args.size() != 1) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "__intrinsic_new takes 1 argument"; } auto arg_type = &args[0]->static_type(); @@ -2375,7 +2371,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } case IntrinsicExpression::Intrinsic::Rand: { if (args.size() != 2) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "Rand takes 2 arguments, received " << args.size(); } CARBON_RETURN_IF_ERROR(ExpectExactType( @@ -2392,7 +2388,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } case IntrinsicExpression::Intrinsic::IntEq: { if (args.size() != 2) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "__intrinsic_int_eq takes 2 arguments"; } CARBON_RETURN_IF_ERROR(ExpectExactType( @@ -2407,7 +2403,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } case IntrinsicExpression::Intrinsic::IntCompare: { if (args.size() != 2) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "__intrinsic_int_compare takes 2 arguments"; } CARBON_RETURN_IF_ERROR(ExpectExactType( @@ -2422,7 +2418,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } case IntrinsicExpression::Intrinsic::StrEq: { if (args.size() != 2) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "__intrinsic_str_eq takes 2 arguments"; } CARBON_RETURN_IF_ERROR(ExpectExactType( @@ -2437,7 +2433,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } case IntrinsicExpression::Intrinsic::StrCompare: { if (args.size() != 2) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "__intrinsic_str_compare takes 2 arguments"; } CARBON_RETURN_IF_ERROR(ExpectExactType( @@ -2452,7 +2448,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } case IntrinsicExpression::Intrinsic::IntBitComplement: if (args.size() != 1) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << intrinsic_exp.name() << " takes 1 argument"; } CARBON_RETURN_IF_ERROR(ExpectExactType( @@ -2467,7 +2463,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, case IntrinsicExpression::Intrinsic::IntLeftShift: case IntrinsicExpression::Intrinsic::IntRightShift: if (args.size() != 2) { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << intrinsic_exp.name() << " takes 2 arguments"; } CARBON_RETURN_IF_ERROR(ExpectExactType( @@ -2531,7 +2527,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, } else if (isa(base_type)) { // Start with an unconstrained type. } else { - return CompilationError(e->source_loc()) + return ProgramError(e->source_loc()) << "expected constraint as first operand of `where` expression, " << "found " << base_type; } @@ -2567,7 +2563,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, map[constraint_type->self_binding()] = type; builder.Add(cast(Substitute(map, constraint))); } else { - return CompilationError(is_clause.constraint().source_loc()) + return ProgramError(is_clause.constraint().source_loc()) << "expression after `is` does not resolve to a " "constraint, found value " << *constraint << " of type " @@ -2613,7 +2609,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, Nonnull size_value, InterpExp(&array_literal.size_expression(), arena_, trace_stream_)); if (cast(size_value)->value() < 0) { - return CompilationError(array_literal.size_expression().source_loc()) + return ProgramError(array_literal.size_expression().source_loc()) << "Array size cannot be negative"; } array_literal.set_static_type(arena_->New()); @@ -2693,7 +2689,7 @@ auto TypeChecker::TypeCheckWhereClause(Nonnull clause, CARBON_RETURN_IF_ERROR(TypeCheckExp(&is_clause.constraint(), impl_scope)); if (!isa( is_clause.constraint().static_type())) { - return CompilationError(is_clause.constraint().source_loc()) + return ProgramError(is_clause.constraint().source_loc()) << "expression after `is` does not resolve to a constraint, " << "found " << is_clause.constraint().static_type(); } @@ -2713,7 +2709,7 @@ auto TypeChecker::TypeCheckWhereClause(Nonnull clause, /*allow_user_defined_conversions=*/false) && !IsImplicitlyConvertible(rhs_type, lhs_type, impl_scope, /*allow_user_defined_conversions=*/false)) { - return CompilationError(clause->source_loc()) + return ProgramError(clause->source_loc()) << "type mismatch between values in `where LHS == RHS`\n" << " LHS type: " << *lhs_type << "\n" << " RHS type: " << *rhs_type; @@ -2746,7 +2742,7 @@ auto TypeChecker::TypeCheckPattern( if (!VisitNestedPatterns(binding.type(), [](const Pattern& pattern) { return !isa(pattern); })) { - return CompilationError(binding.type().source_loc()) + return ProgramError(binding.type().source_loc()) << "The type of a binding pattern cannot contain bindings."; } CARBON_RETURN_IF_ERROR(TypeCheckPattern( @@ -2764,7 +2760,7 @@ auto TypeChecker::TypeCheckPattern( if (!PatternMatch(type, *expected, binding.type().source_loc(), std::nullopt, generic_args, trace_stream_, this->arena_)) { - return CompilationError(binding.type().source_loc()) + return ProgramError(binding.type().source_loc()) << "Type pattern '" << *type << "' does not match actual type '" << **expected << "'"; } @@ -2787,14 +2783,14 @@ auto TypeChecker::TypeCheckPattern( CARBON_ASSIGN_OR_RETURN(Nonnull type, TypeCheckTypeExp(&binding.type(), impl_scope)); if (expected) { - return CompilationError(binding.type().source_loc()) + return ProgramError(binding.type().source_loc()) << "Generic binding may not occur in pattern with expected " "type: " << binding; } binding.set_static_type(type); if (binding.named_as_type_via_dot_self() && !IsTypeOfType(type)) { - return CompilationError(binding.type().source_loc()) + return ProgramError(binding.type().source_loc()) << "`.Self` used in type of non-type binding `" << binding.name() << "`"; } @@ -2817,12 +2813,11 @@ auto TypeChecker::TypeCheckPattern( auto& tuple = cast(*p); std::vector> field_types; if (expected && (*expected)->kind() != Value::Kind::TupleValue) { - return CompilationError(p->source_loc()) << "didn't expect a tuple"; + return ProgramError(p->source_loc()) << "didn't expect a tuple"; } if (expected && tuple.fields().size() != cast(**expected).elements().size()) { - return CompilationError(tuple.source_loc()) - << "tuples of different length"; + return ProgramError(tuple.source_loc()) << "tuples of different length"; } for (size_t i = 0; i < tuple.fields().size(); ++i) { Nonnull field = tuple.fields()[i]; @@ -2851,7 +2846,7 @@ auto TypeChecker::TypeCheckPattern( Nonnull type, InterpExp(&alternative.choice_type(), arena_, trace_stream_)); if (!isa(type)) { - return CompilationError(alternative.source_loc()) + return ProgramError(alternative.source_loc()) << "alternative pattern does not name a choice type."; } const ChoiceType& choice_type = cast(*type); @@ -2863,7 +2858,7 @@ auto TypeChecker::TypeCheckPattern( std::optional> parameter_types = choice_type.FindAlternative(alternative.alternative_name()); if (parameter_types == std::nullopt) { - return CompilationError(alternative.source_loc()) + return ProgramError(alternative.source_loc()) << "'" << alternative.alternative_name() << "' is not an alternative of " << choice_type; } @@ -2919,7 +2914,7 @@ auto TypeChecker::TypeCheckPattern( dyn_cast(&addr_pattern.binding().static_type())) { addr_pattern.set_static_type(&inner_binding_type->type()); } else { - return CompilationError(addr_pattern.source_loc()) + return ProgramError(addr_pattern.source_loc()) << "Type associated with addr must be a pointer type."; } CARBON_ASSIGN_OR_RETURN( @@ -2965,7 +2960,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, expected_type = &clause.pattern().static_type(); } if (patterns.IsRedundant({&clause.pattern()})) { - return CompilationError(clause.pattern().source_loc()) + return ProgramError(clause.pattern().source_loc()) << "unreachable case: all values matched by this case " << "are matched by earlier cases"; } @@ -3009,7 +3004,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, inner_impl_scope, ValueCategory::Var)); } else { - return CompilationError(for_stmt.source_loc()) + return ProgramError(for_stmt.source_loc()) << "expected array type after in, found value of type " << rhs; } @@ -3058,7 +3053,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, CARBON_RETURN_IF_ERROR(TypeCheckExp(&assign.rhs(), impl_scope)); CARBON_RETURN_IF_ERROR(TypeCheckExp(&assign.lhs(), impl_scope)); if (assign.lhs().value_category() != ValueCategory::Var) { - return CompilationError(assign.source_loc()) + return ProgramError(assign.source_loc()) << "Cannot assign to rvalue '" << assign.lhs() << "'"; } CARBON_ASSIGN_OR_RETURN( @@ -3099,7 +3094,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, CARBON_CHECK(IsConcreteType(&ret.value_node().static_type())); if (!IsSameType(&return_term.static_type(), &ret.value_node().static_type(), impl_scope)) { - return CompilationError(ret.value_node().base().source_loc()) + return ProgramError(ret.value_node().base().source_loc()) << "type of returned var `" << ret.value_node().static_type() << "` does not match return type `" << return_term.static_type() << "`"; @@ -3159,7 +3154,7 @@ auto TypeChecker::ExpectReturnOnAllPaths( std::optional> opt_stmt, SourceLocation source_loc) -> ErrorOr { if (!opt_stmt) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "control-flow reaches end of function that provides a `->` " "return type without reaching a return statement"; } @@ -3168,7 +3163,7 @@ auto TypeChecker::ExpectReturnOnAllPaths( case StatementKind::Match: { auto& match = cast(*stmt); if (!IsExhaustive(match)) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "non-exhaustive match may allow control-flow to reach the " "end " "of a function that provides a `->` return type"; @@ -3183,7 +3178,7 @@ auto TypeChecker::ExpectReturnOnAllPaths( case StatementKind::Block: { auto& block = cast(*stmt); if (block.statements().empty()) { - return CompilationError(stmt->source_loc()) + return ProgramError(stmt->source_loc()) << "control-flow reaches end of function that provides a `->` " "return type without reaching a return statement"; } @@ -3213,7 +3208,7 @@ auto TypeChecker::ExpectReturnOnAllPaths( case StatementKind::Break: case StatementKind::Continue: case StatementKind::VariableDefinition: - return CompilationError(stmt->source_loc()) + return ProgramError(stmt->source_loc()) << "control-flow reaches end of function that provides a `->` " "return type without reaching a return statement"; } @@ -3279,7 +3274,7 @@ auto TypeChecker::DeclareCallableDeclaration(Nonnull f, } else { // We have to type-check the body in order to determine the return type. if (!f->body().has_value()) { - return CompilationError(f->return_term().source_loc()) + return ProgramError(f->return_term().source_loc()) << "Function declaration has deduced return type but no body"; } CARBON_RETURN_IF_ERROR(TypeCheckStmt(*f->body(), function_scope)); @@ -3311,7 +3306,7 @@ auto TypeChecker::DeclareCallableDeclaration(Nonnull f, if (f->name() == "Main") { if (!f->return_term().type_expression().has_value()) { - return CompilationError(f->return_term().source_loc()) + return ProgramError(f->return_term().source_loc()) << "`Main` must have an explicit return type"; } CARBON_RETURN_IF_ERROR( @@ -3368,11 +3363,11 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull class_decl, class_scope.AddParent(scope_info.innermost_scope); if (class_decl->extensibility() != ClassExtensibility::None) { - return CompilationError(class_decl->source_loc()) + return ProgramError(class_decl->source_loc()) << "Class prefixes `base` and `abstract` are not supported yet"; } if (class_decl->extends()) { - return CompilationError(class_decl->source_loc()) + return ProgramError(class_decl->source_loc()) << "Class extension with `extends` is not supported yet"; } @@ -3693,7 +3688,7 @@ auto TypeChecker::CheckImplIsDeducible( impl_scope)); for (auto* expected_deduced : deduced_bindings) { if (!deduced_args.count(expected_deduced)) { - return CompilationError(source_loc) + return ProgramError(source_loc) << "parameter `" << *expected_deduced << "` is not deducible from `impl " << *impl_type << " as " << *impl_iface << "`"; @@ -3735,7 +3730,7 @@ auto TypeChecker::CheckImplIsComplete(Nonnull iface_type, }; impl_decl->constraint_type()->VisitEqualValues(expected, visitor); if (!found_any) { - return CompilationError(impl_decl->source_loc()) + return ProgramError(impl_decl->source_loc()) << "implementation missing " << *expected; } else if (!found_value) { // TODO: It's not clear what the right rule is here. Clearly @@ -3743,11 +3738,11 @@ auto TypeChecker::CheckImplIsComplete(Nonnull iface_type, // ... is insufficient to establish a value for either X or Y. // But perhaps we can allow // impl forall [T:! HasX] T as HasY where .Y == .X {} - return CompilationError(impl_decl->source_loc()) + return ProgramError(impl_decl->source_loc()) << "implementation doesn't provide a concrete value for " << *expected; } else if (second_value) { - return CompilationError(impl_decl->source_loc()) + return ProgramError(impl_decl->source_loc()) << "implementation provides multiple values for " << *expected << ": " << **found_value << " and " << **second_value; } @@ -3759,7 +3754,7 @@ auto TypeChecker::CheckImplIsComplete(Nonnull iface_type, std::optional> mem = FindMember(*mem_name, impl_decl->members()); if (!mem.has_value()) { - return CompilationError(impl_decl->source_loc()) + return ProgramError(impl_decl->source_loc()) << "implementation missing " << *mem_name; } @@ -3823,7 +3818,7 @@ auto TypeChecker::CheckAndAddImplBindings( witness, *this); } else { // TODO: Add support for implementing `adapter`s. - return CompilationError(impl_decl->source_loc()) + return ProgramError(impl_decl->source_loc()) << "cannot implement a constraint whose lookup context includes " << *lookup.context; } @@ -3870,7 +3865,7 @@ auto TypeChecker::DeclareImplDeclaration(Nonnull impl_decl, impl_decl->interface().source_loc(), iface_type); } if (!isa(constraint_type)) { - return CompilationError(impl_decl->interface().source_loc()) + return ProgramError(impl_decl->interface().source_loc()) << "expected constraint after `as`, found value of type " << *constraint_type; } @@ -4084,7 +4079,7 @@ auto TypeChecker::DeclareAliasDeclaration(Nonnull alias, TypeCheckExp(&alias->target(), *scope_info.innermost_scope)); if (!IsValidTypeForAliasTarget(&alias->target().static_type())) { - return CompilationError(alias->source_loc()) + return ProgramError(alias->source_loc()) << "invalid target for alias declaration"; } @@ -4164,7 +4159,7 @@ auto TypeChecker::TypeCheckDeclaration( dyn_cast(&var.binding().type()); if (binding_type == nullptr) { // TODO: consider adding support for `auto` - return CompilationError(var.source_loc()) + return ProgramError(var.source_loc()) << "Type of a top-level variable must be an expression."; } if (var.has_initializer()) { @@ -4243,7 +4238,7 @@ auto TypeChecker::DeclareDeclaration(Nonnull d, // Associate the variable name with it's declared type in the // compile-time symbol table. if (!llvm::isa(var.binding().type())) { - return CompilationError(var.binding().type().source_loc()) + return ProgramError(var.binding().type().source_loc()) << "Expected expression for variable type"; } Expression& type = @@ -4349,12 +4344,12 @@ auto TypeChecker::CollectMember(Nonnull enclosing_decl, auto [it, inserted] = encl_members.insert({member_name.value(), member_decl}); if (!inserted) { if (member_decl == it->second) { - return CompilationError(enclosing_decl_loc) + return ProgramError(enclosing_decl_loc) << "Member named " << member_name.value() << " (declared at " << member_decl->source_loc() << ")" << " is being mixed multiple times into " << enclosing_decl_name; } else { - return CompilationError(enclosing_decl_loc) + return ProgramError(enclosing_decl_loc) << "Member named " << member_name.value() << " (declared at " << member_decl->source_loc() << ") cannot be mixed into " << enclosing_decl_name diff --git a/explorer/interpreter/value.cpp b/explorer/interpreter/value.cpp index 725b1e68c5af..280de758c71e 100644 --- a/explorer/interpreter/value.cpp +++ b/explorer/interpreter/value.cpp @@ -65,11 +65,11 @@ static auto GetMember(Nonnull arena, Nonnull v, &impl_witness->bindings()); } } else { - return CompilationError(source_loc) + return ProgramError(source_loc) << "member " << f << " not in " << *witness; } } else { - return RuntimeError(source_loc) + return ProgramError(source_loc) << "member lookup for " << f << " in symbolic " << *witness; } } @@ -78,7 +78,7 @@ static auto GetMember(Nonnull arena, Nonnull v, std::optional> field = cast(*v).FindField(f); if (field == std::nullopt) { - return RuntimeError(source_loc) << "member " << f << " not in " << *v; + return ProgramError(source_loc) << "member " << f << " not in " << *v; } return *field; } @@ -99,7 +99,7 @@ static auto GetMember(Nonnull arena, Nonnull v, std::optional> func = class_type.FindFunction(f); if (func == std::nullopt) { - return RuntimeError(source_loc) << "member " << f << " not in " << *v + return ProgramError(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. @@ -116,7 +116,7 @@ static auto GetMember(Nonnull arena, Nonnull v, case Value::Kind::ChoiceType: { const auto& choice = cast(*v); if (!choice.FindAlternative(f)) { - return RuntimeError(source_loc) + return ProgramError(source_loc) << "alternative " << f << " not in " << *v; } return arena->New(f, choice.name()); @@ -127,7 +127,7 @@ static auto GetMember(Nonnull arena, Nonnull v, std::optional> fun = class_type.FindFunction(f); if (fun == std::nullopt) { - return RuntimeError(source_loc) + return ProgramError(source_loc) << "class function " << f << " not in " << *v; } return arena->New(&(*fun)->declaration(), @@ -167,7 +167,7 @@ static auto SetFieldImpl( return element.name == (*path_begin).name(); }); if (it == elements.end()) { - return RuntimeError(source_loc) + return ProgramError(source_loc) << "field " << (*path_begin).name() << " not in " << *value; } CARBON_ASSIGN_OR_RETURN( @@ -188,7 +188,7 @@ static auto SetFieldImpl( // TODO(geoffromer): update FieldPath to hold integers as well as strings. int index = std::stoi(std::string((*path_begin).name())); if (index < 0 || static_cast(index) >= elements.size()) { - return RuntimeError(source_loc) << "index " << (*path_begin).name() + return ProgramError(source_loc) << "index " << (*path_begin).name() << " out of range in " << *value; } CARBON_ASSIGN_OR_RETURN( diff --git a/explorer/main.cpp b/explorer/main.cpp index b5d0dd37975a..263487223867 100644 --- a/explorer/main.cpp +++ b/explorer/main.cpp @@ -28,7 +28,7 @@ namespace Carbon { namespace cl = llvm::cl; static auto Main(llvm::StringRef default_prelude_file, int argc, char* argv[]) - -> ErrorOr { + -> bool { llvm::setBugReportMsg( "Please report issues to " "https://github.com/carbon-language/carbon-lang/issues and include the " @@ -63,36 +63,55 @@ static auto Main(llvm::StringRef default_prelude_file, int argc, char* argv[]) scoped_trace_stream = std::make_unique(trace_file_name, err); if (err) { - return Error(err.message()); + llvm::errs() << err.message() << "\n"; + return false; } trace_stream = scoped_trace_stream.get(); } } Arena arena; - CARBON_ASSIGN_OR_RETURN(AST ast, - Parse(&arena, input_file_name, parser_debug)); + AST ast; + if (ErrorOr parse_result = Parse(&arena, input_file_name, parser_debug); + parse_result.ok()) { + ast = *std::move(parse_result); + } else { + llvm::errs() << "SYNTAX ERROR: " << parse_result.error() << "\n"; + return false; + } + AddPrelude(prelude_file_name, &arena, &ast.declarations); - // Typecheck and run the parsed program. - CARBON_ASSIGN_OR_RETURN(int return_code, - ExecProgram(&arena, ast, trace_stream)); - // Always print the return code to stdout. - llvm::outs() << "result: " << return_code << "\n"; - // When there's a dedicated trace file, print the return code to it too. - if (scoped_trace_stream) { - **trace_stream << "result: " << return_code << "\n"; + // Semantically analyze the parsed program. + if (ErrorOr analyze_result = AnalyzeProgram(&arena, ast, trace_stream); + analyze_result.ok()) { + ast = *std::move(analyze_result); + } else { + llvm::errs() << "COMPILATION ERROR: " << analyze_result.error() << "\n"; + return false; } - return Success(); + + // Run the program. + if (ErrorOr exec_result = ExecProgram(&arena, ast, trace_stream); + exec_result.ok()) { + // Print the return code to stdout. + llvm::outs() << "result: " << *exec_result << "\n"; + + // When there's a dedicated trace file, print the return code to it too. + if (scoped_trace_stream) { + **trace_stream << "result: " << *exec_result << "\n"; + } + } else { + llvm::errs() << "RUNTIME ERROR: " << exec_result.error() << "\n"; + return false; + } + + return true; } auto ExplorerMain(llvm::StringRef default_prelude_file, int argc, char** argv) -> int { - if (auto result = Main(default_prelude_file, argc, argv); !result.ok()) { - llvm::errs() << result.error() << "\n"; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; + return Main(default_prelude_file, argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE; } } // namespace Carbon diff --git a/explorer/syntax/parse_and_lex_context.cpp b/explorer/syntax/parse_and_lex_context.cpp index a75b16eb89f9..914cddc68f12 100644 --- a/explorer/syntax/parse_and_lex_context.cpp +++ b/explorer/syntax/parse_and_lex_context.cpp @@ -17,7 +17,7 @@ auto ParseAndLexContext::RecordSyntaxError(Error error) -> Parser::symbol_type { auto ParseAndLexContext::RecordSyntaxError(const std::string& message) -> Parser::symbol_type { - return RecordSyntaxError(CompilationError(source_loc()) << message); + return RecordSyntaxError(ProgramError(source_loc()) << message); } } // namespace Carbon diff --git a/explorer/testdata/addr/fail_method_me_misspelled.carbon b/explorer/testdata/addr/fail_method_me_misspelled.carbon index 83ab8aed9dfc..33506bd84f42 100644 --- a/explorer/testdata/addr/fail_method_me_misspelled.carbon +++ b/explorer/testdata/addr/fail_method_me_misspelled.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; class C { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/addr/fail_method_me_misspelled.carbon:[[@LINE+1]]: illegal binding pattern in implicit parameter list + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/addr/fail_method_me_misspelled.carbon:[[@LINE+1]]: illegal binding pattern in implicit parameter list fn F[addr mew: Self*]() {} } diff --git a/explorer/testdata/assoc_const/fail_anonymous.carbon b/explorer/testdata/assoc_const/fail_anonymous.carbon index 8264bf7587c8..4a12a0f09493 100644 --- a/explorer/testdata/assoc_const/fail_anonymous.carbon +++ b/explorer/testdata/assoc_const/fail_anonymous.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; interface Iface { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/assoc_const/fail_anonymous.carbon:[[@LINE+1]]: syntax error, unexpected UNDERSCORE, expecting identifier + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/assoc_const/fail_anonymous.carbon:[[@LINE+1]]: syntax error, unexpected UNDERSCORE, expecting identifier let _:! Type; } diff --git a/explorer/testdata/basic_syntax/fail_block.carbon b/explorer/testdata/basic_syntax/fail_block.carbon index ec380841c38e..0b7e88f43532 100644 --- a/explorer/testdata/basic_syntax/fail_block.carbon +++ b/explorer/testdata/basic_syntax/fail_block.carbon @@ -12,7 +12,7 @@ package ExplorerTest api; fn Main() -> i32 { { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_block.carbon:[[@LINE+1]]: syntax error, unexpected RETURN, expecting PERIOD or RIGHT_CURLY_BRACE + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_block.carbon:[[@LINE+1]]: syntax error, unexpected RETURN, expecting PERIOD or RIGHT_CURLY_BRACE return 0; } } diff --git a/explorer/testdata/basic_syntax/fail_invalid_char.carbon b/explorer/testdata/basic_syntax/fail_invalid_char.carbon index 7731c3366a5c..d430ea7af2d4 100644 --- a/explorer/testdata/basic_syntax/fail_invalid_char.carbon +++ b/explorer/testdata/basic_syntax/fail_invalid_char.carbon @@ -8,5 +8,5 @@ // RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s // AUTOUPDATE: %{explorer} %s -// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_char.carbon:[[@LINE+1]]: invalid character '\xEF' in source file. +// CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_char.carbon:[[@LINE+1]]: invalid character '\xEF' in source file. � diff --git a/explorer/testdata/basic_syntax/fail_invalid_integer.carbon b/explorer/testdata/basic_syntax/fail_invalid_integer.carbon index afc76a2c26b9..76f987fc9568 100644 --- a/explorer/testdata/basic_syntax/fail_invalid_integer.carbon +++ b/explorer/testdata/basic_syntax/fail_invalid_integer.carbon @@ -11,6 +11,6 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_integer.carbon:[[@LINE+1]]: Invalid integer literal: 11111111111111111111111111 + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_integer.carbon:[[@LINE+1]]: Invalid integer literal: 11111111111111111111111111 return 11111111111111111111111111; } diff --git a/explorer/testdata/basic_syntax/fail_invalid_integer_type.carbon b/explorer/testdata/basic_syntax/fail_invalid_integer_type.carbon index be70267d3aec..d642e1e89cc5 100644 --- a/explorer/testdata/basic_syntax/fail_invalid_integer_type.carbon +++ b/explorer/testdata/basic_syntax/fail_invalid_integer_type.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_integer_type.carbon:[[@LINE+1]]: Invalid type literal: i11111111111111111111111111 + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_invalid_integer_type.carbon:[[@LINE+1]]: Invalid type literal: i11111111111111111111111111 var x: i11111111111111111111111111 = 1; return 0; } diff --git a/explorer/testdata/basic_syntax/fail_missing_var.carbon b/explorer/testdata/basic_syntax/fail_missing_var.carbon index 45d1548b40ca..67f6d584cbf7 100644 --- a/explorer/testdata/basic_syntax/fail_missing_var.carbon +++ b/explorer/testdata/basic_syntax/fail_missing_var.carbon @@ -12,7 +12,7 @@ package ExplorerTest api; fn Main() -> i32 { // error - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_missing_var.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary * + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_missing_var.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary * x : i32; return 1; } diff --git a/explorer/testdata/basic_syntax/fail_unknown_intrinsic.carbon b/explorer/testdata/basic_syntax/fail_unknown_intrinsic.carbon index c5724dab6c6f..65c6baf84821 100644 --- a/explorer/testdata/basic_syntax/fail_unknown_intrinsic.carbon +++ b/explorer/testdata/basic_syntax/fail_unknown_intrinsic.carbon @@ -11,6 +11,6 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_unknown_intrinsic.carbon:[[@LINE+1]]: Unknown intrinsic 'nonexistent' + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_unknown_intrinsic.carbon:[[@LINE+1]]: Unknown intrinsic 'nonexistent' return __intrinsic_nonexistent(); } diff --git a/explorer/testdata/basic_syntax/fail_unsupported_integer_type.carbon b/explorer/testdata/basic_syntax/fail_unsupported_integer_type.carbon index e10d6c0a7655..fb17e15a1e6b 100644 --- a/explorer/testdata/basic_syntax/fail_unsupported_integer_type.carbon +++ b/explorer/testdata/basic_syntax/fail_unsupported_integer_type.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_unsupported_integer_type.carbon:[[@LINE+1]]: Only i32 is supported for now: i64 + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_unsupported_integer_type.carbon:[[@LINE+1]]: Only i32 is supported for now: i64 var x: i64 = 1; return 0; } diff --git a/explorer/testdata/basic_syntax/fail_var_named_self.carbon b/explorer/testdata/basic_syntax/fail_var_named_self.carbon index ba2c9cc3f2dc..fbc7803c1f20 100644 --- a/explorer/testdata/basic_syntax/fail_var_named_self.carbon +++ b/explorer/testdata/basic_syntax/fail_var_named_self.carbon @@ -14,7 +14,7 @@ fn Main() -> i32 { // Error: can't use keyword `Self` as the name of a variable. // TODO: Current error message is unclear, better would be to say // something like: unexpected `Self`, expecting identifier - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary * + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary * var Self : i32 = 0; return Self; } diff --git a/explorer/testdata/basic_syntax/not_compare_precedence.carbon b/explorer/testdata/basic_syntax/not_compare_precedence.carbon index 6c5ca091a5ef..bfc37609b026 100644 --- a/explorer/testdata/basic_syntax/not_compare_precedence.carbon +++ b/explorer/testdata/basic_syntax/not_compare_precedence.carbon @@ -11,6 +11,6 @@ package ExplorerTest api; fn CompareBools(a: bool, b: bool) -> bool { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/not_compare_precedence.carbon:[[@LINE+1]]: syntax error, unexpected EQUAL_EQUAL, expecting SEMICOLON + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/not_compare_precedence.carbon:[[@LINE+1]]: syntax error, unexpected EQUAL_EQUAL, expecting SEMICOLON return not a == b; } diff --git a/explorer/testdata/class/fail_class_named_self.carbon b/explorer/testdata/class/fail_class_named_self.carbon index aa88ab44fd16..e65f677a9744 100644 --- a/explorer/testdata/class/fail_class_named_self.carbon +++ b/explorer/testdata/class/fail_class_named_self.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; // Error: Can't use keyword `Self` as the name of a class. -// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/class/fail_class_named_self.carbon:[[@LINE+1]]: syntax error, unexpected SELF, expecting identifier +// CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/class/fail_class_named_self.carbon:[[@LINE+1]]: syntax error, unexpected SELF, expecting identifier class Self { var x: i32; var y: i32; diff --git a/explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon b/explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon index 626dddb6d255..edc3985c8797 100644 --- a/explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon +++ b/explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon @@ -12,7 +12,7 @@ package ExplorerTest api; fn Main() -> i32 { var x: i32 = 0; - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon:[[@LINE+1]]: syntax error, unexpected identifier, expecting LEFT_CURLY_BRACE + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/experimental_continuation/fail_continuation_syntax.carbon:[[@LINE+1]]: syntax error, unexpected identifier, expecting LEFT_CURLY_BRACE __continuation k x = 3; __run k; return x; diff --git a/explorer/testdata/generic_function/fail_missing_exclam.carbon b/explorer/testdata/generic_function/fail_missing_exclam.carbon index 6e08c8bd963a..af13759f489a 100644 --- a/explorer/testdata/generic_function/fail_missing_exclam.carbon +++ b/explorer/testdata/generic_function/fail_missing_exclam.carbon @@ -10,7 +10,7 @@ package ExplorerTest api; -// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_function/fail_missing_exclam.carbon:[[@LINE+1]]: illegal binding pattern in implicit parameter list +// CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/generic_function/fail_missing_exclam.carbon:[[@LINE+1]]: illegal binding pattern in implicit parameter list fn F[T: Type](); fn Main() -> i32 { diff --git a/explorer/testdata/global_variable/fail_named_self.carbon b/explorer/testdata/global_variable/fail_named_self.carbon index f97fdd6e993b..a22596ec5fed 100644 --- a/explorer/testdata/global_variable/fail_named_self.carbon +++ b/explorer/testdata/global_variable/fail_named_self.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; // Error: global variable may not be named with keyword `Self`. -// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/global_variable/fail_named_self.carbon:[[@LINE+1]]: syntax error, unexpected SELF, expecting identifier +// CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/global_variable/fail_named_self.carbon:[[@LINE+1]]: syntax error, unexpected SELF, expecting identifier var Self: i32 = 0; fn Main() -> i32 { diff --git a/explorer/testdata/impl/fail_bad_member_kind.carbon b/explorer/testdata/impl/fail_bad_member_kind.carbon index 189993f2156c..72be158e69aa 100644 --- a/explorer/testdata/impl/fail_bad_member_kind.carbon +++ b/explorer/testdata/impl/fail_bad_member_kind.carbon @@ -16,7 +16,7 @@ interface A { } external impl i32 as A { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_bad_member_kind.carbon:[[@LINE+1]]: syntax error, unexpected CLASS, expecting ALIAS or FN or RIGHT_CURLY_BRACE + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/impl/fail_bad_member_kind.carbon:[[@LINE+1]]: syntax error, unexpected CLASS, expecting ALIAS or FN or RIGHT_CURLY_BRACE class T {} } diff --git a/explorer/testdata/import/fail_order.carbon b/explorer/testdata/import/fail_order.carbon index 073437acf1de..93724a0c3ad5 100644 --- a/explorer/testdata/import/fail_order.carbon +++ b/explorer/testdata/import/fail_order.carbon @@ -14,5 +14,5 @@ fn Main() -> i32 { return 0; } -// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/import/fail_order.carbon:[[@LINE+1]]: syntax error, unexpected IMPORT, expecting END_OF_FILE +// CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/import/fail_order.carbon:[[@LINE+1]]: syntax error, unexpected IMPORT, expecting END_OF_FILE import ExplorerTest library "Nonexistent"; diff --git a/explorer/testdata/interface/fail_bad_member_kind.carbon b/explorer/testdata/interface/fail_bad_member_kind.carbon index 1bc89c0ff81c..c101a5e96725 100644 --- a/explorer/testdata/interface/fail_bad_member_kind.carbon +++ b/explorer/testdata/interface/fail_bad_member_kind.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; interface Bad { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_bad_member_kind.carbon:[[@LINE+1]]: syntax error, unexpected VAR, expecting FN or LET or RIGHT_CURLY_BRACE + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/interface/fail_bad_member_kind.carbon:[[@LINE+1]]: syntax error, unexpected VAR, expecting FN or LET or RIGHT_CURLY_BRACE var V: i32; } diff --git a/explorer/testdata/interface/fail_use_symbolic_member.carbon b/explorer/testdata/interface/fail_use_symbolic_member.carbon index 9c39b4495bb9..096016b327a8 100644 --- a/explorer/testdata/interface/fail_use_symbolic_member.carbon +++ b/explorer/testdata/interface/fail_use_symbolic_member.carbon @@ -14,7 +14,7 @@ interface X { fn F() -> Type; } -// CHECK: RUNTIME ERROR: {{.*}}/explorer/testdata/interface/fail_use_symbolic_member.carbon:[[@LINE+1]]: member lookup for F in symbolic witness for T:! X +// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_use_symbolic_member.carbon:[[@LINE+1]]: member lookup for F in symbolic witness for T:! X fn G[T:! X]() -> T.F() { return {}; } diff --git a/explorer/testdata/let/fail_global_named_self.carbon b/explorer/testdata/let/fail_global_named_self.carbon index 73895eeef484..5afa959aeb33 100644 --- a/explorer/testdata/let/fail_global_named_self.carbon +++ b/explorer/testdata/let/fail_global_named_self.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; // Error: Can't use keyword `Self` as the name of a global. -// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_global_named_self.carbon:[[@LINE+1]]: syntax error, unexpected SELF, expecting identifier +// CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/let/fail_global_named_self.carbon:[[@LINE+1]]: syntax error, unexpected SELF, expecting identifier let Self: i32 = 10; fn Main() -> i32 { diff --git a/explorer/testdata/let/fail_local_named_self.carbon b/explorer/testdata/let/fail_local_named_self.carbon index f60aece17df5..bfab9364314c 100644 --- a/explorer/testdata/let/fail_local_named_self.carbon +++ b/explorer/testdata/let/fail_local_named_self.carbon @@ -12,7 +12,7 @@ package ExplorerTest api; fn Main() -> i32 { // Error: Can't use keyword `Self` as the name of a local. - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_local_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary * + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/let/fail_local_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary * let Self: auto = 10; return 0; } diff --git a/explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon b/explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon index b3097b4d2951..367b67796153 100644 --- a/explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon +++ b/explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon:[[@LINE+1]]: syntax error, unexpected LET + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_context_nested.carbon:[[@LINE+1]]: syntax error, unexpected LET let (var a: auto, b: auto, c: auto, var (d: auto, let e: auto)) = (1, 2, 3, (4, 5)); return 0; diff --git a/explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon b/explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon index 7a847f6bd613..5425d423ca2a 100644 --- a/explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon +++ b/explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon:[[@LINE+1]]: syntax error, unexpected LET + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_in_var.carbon:[[@LINE+1]]: syntax error, unexpected LET var (var a: auto, b: auto, let c: auto, d: auto) = (1, 2, 3, 4); return 0; } diff --git a/explorer/testdata/match/fail_not_alternative.carbon b/explorer/testdata/match/fail_not_alternative.carbon index 36b7536d8433..a647ee1abe56 100644 --- a/explorer/testdata/match/fail_not_alternative.carbon +++ b/explorer/testdata/match/fail_not_alternative.carbon @@ -7,13 +7,13 @@ // RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \ // RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s // AUTOUPDATE: %{explorer} %s -// CHECK: PROGRAM ERROR: {{.*}}/explorer/testdata/match/fail_not_alternative.carbon:17: Alternative pattern must have the form of a field access. package ExplorerTest api; fn Main() -> i32 { var x: i32 = 0; match (x) { + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/match/fail_not_alternative.carbon:[[@LINE+1]]: Alternative pattern must have the form of a field access. case i32(n: i32) => { return 1; } diff --git a/explorer/testdata/mixin/fail_mix_in_global.carbon b/explorer/testdata/mixin/fail_mix_in_global.carbon index b472eae7d2ea..39f99f4e7bb5 100644 --- a/explorer/testdata/mixin/fail_mix_in_global.carbon +++ b/explorer/testdata/mixin/fail_mix_in_global.carbon @@ -16,7 +16,7 @@ __mixin Operations { } } -// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/mixin/fail_mix_in_global.carbon:[[@LINE+1]]: syntax error, unexpected MIX, expecting END_OF_FILE +// CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/mixin/fail_mix_in_global.carbon:[[@LINE+1]]: syntax error, unexpected MIX, expecting END_OF_FILE __mix Operations; class Point { diff --git a/explorer/testdata/mixin/fail_mix_in_impl.carbon b/explorer/testdata/mixin/fail_mix_in_impl.carbon index 7b0c44be46dd..2fb52bf159e8 100644 --- a/explorer/testdata/mixin/fail_mix_in_impl.carbon +++ b/explorer/testdata/mixin/fail_mix_in_impl.carbon @@ -21,7 +21,7 @@ interface A { } external impl i32 as A { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/mixin/fail_mix_in_impl.carbon:[[@LINE+1]]: syntax error, unexpected MIX, expecting ALIAS or FN or RIGHT_CURLY_BRACE + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/mixin/fail_mix_in_impl.carbon:[[@LINE+1]]: syntax error, unexpected MIX, expecting ALIAS or FN or RIGHT_CURLY_BRACE __mix Operations; fn F() {} } diff --git a/explorer/testdata/package/fail_missing.carbon b/explorer/testdata/package/fail_missing.carbon index ef3260ee95cd..a12921624381 100644 --- a/explorer/testdata/package/fail_missing.carbon +++ b/explorer/testdata/package/fail_missing.carbon @@ -8,7 +8,7 @@ // RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s // AUTOUPDATE: %{explorer} %s -// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/package/fail_missing.carbon:[[@LINE+1]]: syntax error, unexpected FN, expecting PACKAGE +// CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/package/fail_missing.carbon:[[@LINE+1]]: syntax error, unexpected FN, expecting PACKAGE fn Main() -> i32 { return 0; } diff --git a/explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon b/explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon index 98411802bc18..cf4e2d98f2e0 100644 --- a/explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon +++ b/explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon:[[@LINE+1]]: Invalid block string: Should end with triple quotes: error: closing """ + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_block_quotes_not_on_own_line.carbon:[[@LINE+1]]: Invalid block string: Should end with triple quotes: error: closing """ var s: String = """ error: closing """ is not on its own line. """; diff --git a/explorer/testdata/string/fail_hex_lower.carbon b/explorer/testdata/string/fail_hex_lower.carbon index 1e5bf629c5f3..77ce13270640 100644 --- a/explorer/testdata/string/fail_hex_lower.carbon +++ b/explorer/testdata/string/fail_hex_lower.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_hex_lower.carbon:[[@LINE+1]]: Invalid escaping in string: "str\xaa" + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_hex_lower.carbon:[[@LINE+1]]: Invalid escaping in string: "str\xaa" Print("str\xaa"); return 0; } diff --git a/explorer/testdata/string/fail_hex_truncated.carbon b/explorer/testdata/string/fail_hex_truncated.carbon index d480dfde3f14..db532d87c583 100644 --- a/explorer/testdata/string/fail_hex_truncated.carbon +++ b/explorer/testdata/string/fail_hex_truncated.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_hex_truncated.carbon:[[@LINE+1]]: Invalid escaping in string: "str\x" + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_hex_truncated.carbon:[[@LINE+1]]: Invalid escaping in string: "str\x" Print("str\x"); return 0; } diff --git a/explorer/testdata/string/fail_invalid_escape.carbon b/explorer/testdata/string/fail_invalid_escape.carbon index 6c143987a089..dad9bd663c8a 100644 --- a/explorer/testdata/string/fail_invalid_escape.carbon +++ b/explorer/testdata/string/fail_invalid_escape.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_invalid_escape.carbon:[[@LINE+1]]: Invalid escaping in string: "str\e" + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_invalid_escape.carbon:[[@LINE+1]]: Invalid escaping in string: "str\e" Print("str\e"); return 0; } diff --git a/explorer/testdata/string/fail_newline.carbon b/explorer/testdata/string/fail_newline.carbon index a279f25ce561..0c4657ad00e5 100644 --- a/explorer/testdata/string/fail_newline.carbon +++ b/explorer/testdata/string/fail_newline.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_newline.carbon:[[@LINE+2]]: missing closing quote in single-line string: "new + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_newline.carbon:[[@LINE+2]]: missing closing quote in single-line string: "new // CHECK-EMPTY: Print("new line"); diff --git a/explorer/testdata/string/fail_octal.carbon b/explorer/testdata/string/fail_octal.carbon index efdb5a5f815f..5ecb54f0df65 100644 --- a/explorer/testdata/string/fail_octal.carbon +++ b/explorer/testdata/string/fail_octal.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_octal.carbon:[[@LINE+1]]: Invalid escaping in string: "str\01" + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_octal.carbon:[[@LINE+1]]: Invalid escaping in string: "str\01" Print("str\01"); return 0; } diff --git a/explorer/testdata/string/fail_raw_block_more_hash_tags_on_left.carbon b/explorer/testdata/string/fail_raw_block_more_hash_tags_on_left.carbon index ef38648787c6..5ecd5defcc6f 100644 --- a/explorer/testdata/string/fail_raw_block_more_hash_tags_on_left.carbon +++ b/explorer/testdata/string/fail_raw_block_more_hash_tags_on_left.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_raw_block_more_hash_tags_on_left.carbon:[[@LINE+1]]: Unexpected end of file + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_raw_block_more_hash_tags_on_left.carbon:[[@LINE+1]]: Unexpected end of file var s: String = ##""" error: there are more #s on the left than the right. """#; diff --git a/explorer/testdata/string/fail_raw_block_more_hash_tags_on_right.carbon b/explorer/testdata/string/fail_raw_block_more_hash_tags_on_right.carbon index d92ac406a514..8575aee07ca7 100644 --- a/explorer/testdata/string/fail_raw_block_more_hash_tags_on_right.carbon +++ b/explorer/testdata/string/fail_raw_block_more_hash_tags_on_right.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_raw_block_more_hash_tags_on_right.carbon:[[@LINE+1]]: invalid character '\x23' in source file. + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_raw_block_more_hash_tags_on_right.carbon:[[@LINE+1]]: invalid character '\x23' in source file. var s: String = #""" error: there are more #s on the right than the left. """##; diff --git a/explorer/testdata/string/fail_raw_block_quotes_not_on_own_line.carbon b/explorer/testdata/string/fail_raw_block_quotes_not_on_own_line.carbon index dfbaec9f174f..245937c9fcd6 100644 --- a/explorer/testdata/string/fail_raw_block_quotes_not_on_own_line.carbon +++ b/explorer/testdata/string/fail_raw_block_quotes_not_on_own_line.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_raw_block_quotes_not_on_own_line.carbon:[[@LINE+1]]: Invalid block string: Should end with triple quotes: error: closing """ + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_raw_block_quotes_not_on_own_line.carbon:[[@LINE+1]]: Invalid block string: Should end with triple quotes: error: closing """ var s: String = #""" error: closing """# is not on its own line. """#; diff --git a/explorer/testdata/string/fail_raw_block_single_line.carbon b/explorer/testdata/string/fail_raw_block_single_line.carbon index cae3b5e9f514..a858b8a5debe 100644 --- a/explorer/testdata/string/fail_raw_block_single_line.carbon +++ b/explorer/testdata/string/fail_raw_block_single_line.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn CompareStr(s: String) -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_raw_block_single_line.carbon:[[@LINE+1]]: Invalid block string: Too few lines + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_raw_block_single_line.carbon:[[@LINE+1]]: Invalid block string: Too few lines if (s == #"""raw string literal starting with """#) { return 0; } diff --git a/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon b/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon index 75dc531d3de4..5013d8e6f5cc 100644 --- a/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon +++ b/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn CompareStr(s: String) -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon:[[@LINE+2]]: missing closing quote in single-line string: ##"str"#) { + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon:[[@LINE+2]]: missing closing quote in single-line string: ##"str"#) { // CHECK-EMPTY: if (s == ##"str"#) { return 0; diff --git a/explorer/testdata/string/fail_raw_more_hash_tags_on_right.carbon b/explorer/testdata/string/fail_raw_more_hash_tags_on_right.carbon index 26a93c578a84..669e9dea6ea0 100644 --- a/explorer/testdata/string/fail_raw_more_hash_tags_on_right.carbon +++ b/explorer/testdata/string/fail_raw_more_hash_tags_on_right.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn CompareStr(s: String) -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_raw_more_hash_tags_on_right.carbon:[[@LINE+1]]: invalid character '\x23' in source file. + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_raw_more_hash_tags_on_right.carbon:[[@LINE+1]]: invalid character '\x23' in source file. if (s == "str"#) { return 0; } diff --git a/explorer/testdata/string/fail_tab.carbon b/explorer/testdata/string/fail_tab.carbon index 5a031c5fbe91..9ec19fddb8da 100644 --- a/explorer/testdata/string/fail_tab.carbon +++ b/explorer/testdata/string/fail_tab.carbon @@ -11,7 +11,7 @@ package ExplorerTest api; fn Main() -> i32 { - // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/string/fail_tab.carbon:[[@LINE+1]]: Invalid escaping in string: "new line" + // CHECK: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_tab.carbon:[[@LINE+1]]: Invalid escaping in string: "new line" Print("new line"); return 0; } diff --git a/explorer/testdata/tuple/fail_index_var.carbon b/explorer/testdata/tuple/fail_index_var.carbon index d9ef64031c4d..31c86765d248 100644 --- a/explorer/testdata/tuple/fail_index_var.carbon +++ b/explorer/testdata/tuple/fail_index_var.carbon @@ -13,6 +13,6 @@ package ExplorerTest api; fn Main() -> i32 { var x: auto = (0, 1); var index: i32 = 0; - // CHECK: RUNTIME ERROR: {{.*}}/explorer/testdata/tuple/fail_index_var.carbon:[[@LINE+1]]: could not find `index: i32` + // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/tuple/fail_index_var.carbon:[[@LINE+1]]: could not find `index: i32` return x[index]; } diff --git a/explorer/update_checks.py b/explorer/update_checks.py index 6b15efab50a6..26dcb0476d8c 100755 --- a/explorer/update_checks.py +++ b/explorer/update_checks.py @@ -27,7 +27,9 @@ _AUTOUPDATE_MARKER = "// AUTOUPDATE: " _NOAUTOUPDATE_MARKER = "// NOAUTOUPDATE" # A regexp matching lines that contain line number references. -_LINE_NUMBER_RE = r"((?:COMPILATION|RUNTIME) ERROR: [^:]*:)([1-9][0-9]*)(:.*)" +_LINE_NUMBER_RE = ( + r"((?:SYNTAX|COMPILATION|RUNTIME) ERROR: [^:]*:)([1-9][0-9]*)(:.*)" +) def _get_tests() -> Set[str]: