Switch from llvm::errs()+exit() to FATAL_USER_ERROR() stream-based handling. (#670)

This is intended to:

- Standardize use of line_num (and highlight where no line_num is available).
- Standardize indications of runtime/compilation errors.
- Make it incrementally easier to write new errors.

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This commit is contained in:
Jon Meow
2021-07-28 10:47:33 -07:00
committed by GitHub
co-authored by Chandler Carruth
parent dcc694c2e0
commit f0af3cb795
24 changed files with 206 additions and 170 deletions
+2 -3
View File
@@ -169,9 +169,8 @@ auto Expression::MakeTupleLiteral(int line_num,
for (auto& arg : args) {
if (arg.name == "") {
if (seen_named_member) {
FatalUserError()
<< line_num
<< ": positional members must come before named members";
FATAL_USER_ERROR(line_num)
<< "positional members must come before named members";
}
arg.name = std::to_string(i);
++i;
+35 -10
View File
@@ -11,28 +11,53 @@
namespace Carbon {
// Prints an error and exits. This should be used for non-recoverable errors
// with user input.
//
// For example:
// FatalUserError() << "Input is not valid!";
class FatalUserError {
namespace ErrorInternal {
// An error-printing stream that exits on destruction.
class ExitingStream {
public:
FatalUserError() { llvm::errs() << "ERROR: "; }
~FatalUserError() {
// Finish with a newline.
// Ends the error with a newline and exits.
LLVM_ATTRIBUTE_NORETURN virtual ~ExitingStream() {
llvm::errs() << "\n";
exit(-1);
}
// Forward output to llvm::errs.
template <typename T>
FatalUserError& operator<<(const T& message) {
ExitingStream& operator<<(const T& message) {
llvm::errs() << message;
return *this;
}
};
} // namespace ErrorInternal
// Prints an error and exits. This should be used for non-recoverable errors
// with user input.
//
// For example:
// FATAL_USER_ERROR(line_num) << "Line is bad!";
// FATAL_USER_ERROR_NO_LINE() << "Application is bad!";
//
// Where possible, try to identify the error as a compilation error or runtime
// error. The generic user error option is provided as a fallback for cases that
// don't fit either of those classifications.
#define FATAL_USER_ERROR_NO_LINE() ErrorInternal::ExitingStream() << "ERROR: "
#define FATAL_USER_ERROR(line) FATAL_USER_ERROR_NO_LINE() << line << ": "
#define FATAL_COMPILATION_ERROR_NO_LINE() \
ErrorInternal::ExitingStream() << "COMPILATION ERROR: "
#define FATAL_COMPILATION_ERROR(line) \
FATAL_COMPILATION_ERROR_NO_LINE() << line << ": "
#define FATAL_RUNTIME_ERROR_NO_LINE() \
ErrorInternal::ExitingStream() << "RUNTIME ERROR: "
#define FATAL_RUNTIME_ERROR(line) FATAL_RUNTIME_ERROR_NO_LINE() << line << ": "
} // namespace Carbon
#endif // EXECUTABLE_SEMANTICS_COMMON_ERROR_H_
+23 -1
View File
@@ -7,9 +7,31 @@
#include "gtest/gtest.h"
namespace Carbon {
namespace {
TEST(ErrorTest, FatalUserError) {
ASSERT_DEATH({ FatalUserError() << "test"; }, "ERROR: test\n");
ASSERT_DEATH({ FATAL_RUNTIME_ERROR_NO_LINE() << "test"; }, "ERROR: test\n");
}
TEST(ErrorTest, FatalRuntimeError) {
ASSERT_DEATH({ FATAL_RUNTIME_ERROR_NO_LINE() << "test"; },
"RUNTIME ERROR: test\n");
}
TEST(ErrorTest, FatalCompilationError) {
ASSERT_DEATH({ FATAL_COMPILATION_ERROR_NO_LINE() << "test"; },
"COMPILATION ERROR: test\n");
}
TEST(ErrorTest, FatalUserErrorLine) {
ASSERT_DEATH({ FATAL_USER_ERROR(1) << "test"; }, "ERROR: 1: test\n");
}
auto NoReturnRequired() -> int { FATAL_USER_ERROR_NO_LINE() << "test"; }
TEST(ErrorTest, NoReturnRequired) {
ASSERT_DEATH({ NoReturnRequired(); }, "ERROR: test\n");
}
} // namespace
} // namespace Carbon
+5 -5
View File
@@ -4,6 +4,7 @@
#include "executable_semantics/interpreter/heap.h"
#include "executable_semantics/common/error.h"
#include "llvm/ADT/StringExtras.h"
namespace Carbon {
@@ -33,9 +34,9 @@ void Heap::Write(const Address& a, const Value* v, int line_num) {
void Heap::CheckAlive(const Address& address, int line_num) {
if (!alive_[address.index]) {
llvm::errs() << line_num << ": undefined behavior: access to dead value "
<< *values_[address.index] << "\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num)
<< ": undefined behavior: access to dead value "
<< *values_[address.index];
}
}
@@ -44,8 +45,7 @@ void Heap::Deallocate(const Address& address) {
if (alive_[address.index]) {
alive_[address.index] = false;
} else {
llvm::errs() << "runtime error, deallocating an already dead value\n";
exit(-1);
FATAL_RUNTIME_ERROR_NO_LINE() << "deallocating an already dead value";
}
}
@@ -14,6 +14,7 @@
#include "common/check.h"
#include "executable_semantics/ast/expression.h"
#include "executable_semantics/ast/function_definition.h"
#include "executable_semantics/common/error.h"
#include "executable_semantics/common/tracing_flag.h"
#include "executable_semantics/interpreter/action.h"
#include "executable_semantics/interpreter/frame.h"
@@ -185,11 +186,7 @@ void CallFunction(int line_num, std::vector<const Value*> operas,
std::optional<Env> matches =
PatternMatch(operas[0]->GetFunctionValue().param, operas[1], globals,
&params, line_num);
if (!matches) {
llvm::errs()
<< "internal error in call_function, pattern match failed\n";
exit(-1);
}
CHECK(matches) << "internal error in call_function, pattern match failed";
// Create the new frame and push it on the stack
auto* scope = new Scope(*matches, params);
auto* frame = new Frame(operas[0]->GetFunctionValue().name, Stack(scope),
@@ -215,19 +212,15 @@ void CallFunction(int line_num, std::vector<const Value*> operas,
break;
}
default:
llvm::errs() << line_num << ": in call, expected a function, not "
<< *operas[0] << "\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num)
<< "in call, expected a function, not " << *operas[0];
}
}
void DeallocateScope(int line_num, Scope* scope) {
for (const auto& l : scope->locals) {
std::optional<Address> a = scope->values.Get(l);
if (!a) {
llvm::errs() << "internal error in DeallocateScope\n";
exit(-1);
}
CHECK(a);
state->heap.Deallocate(*a);
}
}
@@ -277,18 +270,16 @@ auto PatternMatch(const Value* p, const Value* v, Env values,
case ValKind::TupleValue: {
if (p->GetTupleValue().elements.size() !=
v->GetTupleValue().elements.size()) {
llvm::errs()
<< "runtime error: arity mismatch in tuple pattern match\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num)
<< "arity mismatch in tuple pattern match";
}
for (const TupleElement& pattern_element :
p->GetTupleValue().elements) {
const Value* value_field =
v->GetTupleValue().FindField(pattern_element.name);
if (value_field == nullptr) {
llvm::errs() << "runtime error: field " << pattern_element.name
<< "not in " << *v << "\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num)
<< "field " << pattern_element.name << "not in " << *v;
}
std::optional<Env> matches = PatternMatch(
pattern_element.value, value_field, values, vars, line_num);
@@ -365,18 +356,16 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) {
case ValKind::TupleValue: {
if (pat->GetTupleValue().elements.size() !=
val->GetTupleValue().elements.size()) {
llvm::errs()
<< "runtime error: arity mismatch in tuple pattern match\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num)
<< "arity mismatch in tuple pattern match";
}
for (const TupleElement& pattern_element :
pat->GetTupleValue().elements) {
const Value* value_field =
val->GetTupleValue().FindField(pattern_element.name);
if (value_field == nullptr) {
llvm::errs() << "runtime error: field " << pattern_element.name
<< "not in " << *val << "\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num)
<< "field " << pattern_element.name << "not in " << *val;
}
PatternAssignment(pattern_element.value, value_field, line_num);
}
@@ -394,13 +383,11 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) {
case ValKind::AlternativeValue: {
switch (val->tag()) {
case ValKind::AlternativeValue: {
if (pat->GetAlternativeValue().choice_name !=
val->GetAlternativeValue().choice_name ||
pat->GetAlternativeValue().alt_name !=
val->GetAlternativeValue().alt_name) {
llvm::errs() << "internal error in pattern assignment\n";
exit(-1);
}
CHECK(pat->GetAlternativeValue().choice_name ==
val->GetAlternativeValue().choice_name &&
pat->GetAlternativeValue().alt_name ==
val->GetAlternativeValue().alt_name)
<< "internal error in pattern assignment";
PatternAssignment(pat->GetAlternativeValue().argument,
val->GetAlternativeValue().argument, line_num);
break;
@@ -415,10 +402,8 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) {
break;
}
default:
if (!ValueEqual(pat, val, line_num)) {
llvm::errs() << "internal error in pattern assignment\n";
exit(-1);
}
CHECK(ValueEqual(pat, val, line_num))
<< "internal error in pattern assignment";
}
}
@@ -438,9 +423,9 @@ void StepLvalue() {
std::optional<Address> pointer =
CurrentEnv(state).Get(exp->GetIdentifierExpression().name);
if (!pointer) {
llvm::errs() << exp->line_num << ": could not find `"
<< exp->GetIdentifierExpression().name << "`\n";
exit(-1);
FATAL_RUNTIME_ERROR(exp->line_num)
<< ": could not find `" << exp->GetIdentifierExpression().name
<< "`";
}
const Value* v = Value::MakePointerValue(*pointer);
frame->todo.Pop();
@@ -520,8 +505,8 @@ void StepLvalue() {
case ExpressionKind::AutoTypeLiteral:
case ExpressionKind::ContinuationTypeLiteral:
case ExpressionKind::BindingExpression: {
llvm::errs() << "Can't treat expression as lvalue: " << *exp << "\n";
exit(-1);
FATAL_RUNTIME_ERROR_NO_LINE()
<< "Can't treat expression as lvalue: " << *exp;
}
}
}
@@ -569,20 +554,16 @@ void StepExp() {
std::string f = std::to_string(act->results[1]->GetIntValue());
const Value* field = tuple->GetTupleValue().FindField(f);
if (field == nullptr) {
llvm::errs() << "runtime error, field " << f << " not in "
<< *tuple << "\n";
exit(-1);
FATAL_RUNTIME_ERROR_NO_LINE()
<< "field " << f << " not in " << *tuple;
}
frame->todo.Pop(1);
frame->todo.Push(Action::MakeValAction(field));
break;
}
default:
llvm::errs()
<< "runtime type error, expected a tuple in field access, "
"not "
<< *tuple << "\n";
exit(-1);
FATAL_RUNTIME_ERROR_NO_LINE()
<< "expected a tuple in field access, not " << *tuple;
}
}
break;
@@ -636,9 +617,9 @@ void StepExp() {
std::optional<Address> pointer =
CurrentEnv(state).Get(exp->GetIdentifierExpression().name);
if (!pointer) {
llvm::errs() << exp->line_num << ": could not find `"
<< exp->GetIdentifierExpression().name << "`\n";
exit(-1);
FATAL_RUNTIME_ERROR(exp->line_num)
<< ": could not find `" << exp->GetIdentifierExpression().name
<< "`";
}
const Value* pointee = state->heap.Read(*pointer, exp->line_num);
frame->todo.Pop(1);
@@ -946,12 +927,9 @@ void StepStmt() {
std::optional<Env> matches =
PatternMatch(p, v, frame->scopes.Top()->values,
&frame->scopes.Top()->locals, stmt->line_num);
if (!matches) {
llvm::errs()
<< stmt->line_num
<< ": internal error in variable definition, match failed\n";
exit(-1);
}
CHECK(matches)
<< stmt->line_num
<< ": internal error in variable definition, match failed";
frame->scopes.Top()->values = *matches;
frame->todo.Pop(1);
}
@@ -1101,9 +1079,8 @@ void StepStmt() {
void Step() {
Frame* frame = state->stack.Top();
if (frame->todo.IsEmpty()) {
llvm::errs() << "runtime error: fell off end of function " << frame->name
<< " without `return`\n";
exit(-1);
FATAL_RUNTIME_ERROR_NO_LINE()
<< "fell off end of function " << frame->name << " without `return`";
}
Action* act = frame->todo.Top();
+43 -70
View File
@@ -20,18 +20,18 @@ namespace Carbon {
void ExpectType(int line_num, const std::string& context, const Value* expected,
const Value* actual) {
if (!TypeEqual(expected, actual)) {
FatalUserError() << line_num << ": type error in " << context << "\n"
<< "expected: " << *expected << "\n"
<< "actual: " << *actual;
FATAL_COMPILATION_ERROR(line_num) << "type error in " << context << "\n"
<< "expected: " << *expected << "\n"
<< "actual: " << *actual;
}
}
void ExpectPointerType(int line_num, const std::string& context,
const Value* actual) {
if (actual->tag() != ValKind::PointerType) {
FatalUserError() << line_num << ": type error in " << context << "\n"
<< "expected a pointer type\n"
<< "actual: " << *actual;
FATAL_COMPILATION_ERROR(line_num) << "type error in " << context << "\n"
<< "expected a pointer type\n"
<< "actual: " << *actual;
}
}
@@ -258,20 +258,13 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
switch (e->tag()) {
case ExpressionKind::BindingExpression: {
if (context != TCContext::PatternContext) {
llvm::errs()
<< e->line_num
<< ": compilation error, pattern variables are only allowed in "
"pattern context"
<< "\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num)
<< "pattern variables are only allowed in pattern context";
}
auto t = InterpExp(values, e->GetBindingExpression().type);
if (t->tag() == ValKind::AutoType) {
if (expected == nullptr) {
llvm::errs() << e->line_num
<< ": compilation error, auto not allowed here"
<< "\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num) << " auto not allowed here";
} else {
t = expected;
}
@@ -297,18 +290,15 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
std::string f = std::to_string(i);
const Value* field_t = t->GetTupleValue().FindField(f);
if (field_t == nullptr) {
llvm::errs() << e->line_num << ": compilation error, field " << f
<< " is not in the tuple " << *t << "\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num)
<< "field " << f << " is not in the tuple " << *t;
}
auto new_e = Expression::MakeIndexExpression(
e->line_num, res.exp, Expression::MakeIntLiteral(e->line_num, i));
return TCResult(new_e, field_t, res.types);
}
default:
llvm::errs() << e->line_num
<< ": compilation error, expected a tuple\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num) << "expected a tuple";
}
}
case ExpressionKind::TupleLiteral: {
@@ -316,15 +306,11 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
std::vector<TupleElement> arg_types;
auto new_types = types;
if (expected && expected->tag() != ValKind::TupleValue) {
llvm::errs() << e->line_num
<< ": compilation error, didn't expect a tuple\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num) << "didn't expect a tuple";
}
if (expected && e->GetTupleLiteral().fields.size() !=
expected->GetTupleValue().elements.size()) {
llvm::errs() << e->line_num
<< ": compilation error, tuples of different length\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num) << "tuples of different length";
}
int i = 0;
for (auto arg = e->GetTupleLiteral().fields.begin();
@@ -332,12 +318,10 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
const Value* arg_expected = nullptr;
if (expected && expected->tag() == ValKind::TupleValue) {
if (expected->GetTupleValue().elements[i].name != arg->name) {
llvm::errs()
<< e->line_num
<< ": compilation error, field names do not match, expected "
FATAL_COMPILATION_ERROR(e->line_num)
<< "field names do not match, expected "
<< expected->GetTupleValue().elements[i].name << " but got "
<< arg->name << "\n";
exit(-1);
<< arg->name;
}
arg_expected = expected->GetTupleValue().elements[i].value;
}
@@ -373,11 +357,10 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
return TCResult(new_e, method.second, res.types);
}
}
llvm::errs() << e->line_num << ": compilation error, struct "
<< t->GetStructType().name
<< " does not have a field named "
<< e->GetFieldAccessExpression().field << "\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num)
<< "struct " << t->GetStructType().name
<< " does not have a field named "
<< e->GetFieldAccessExpression().field;
case ValKind::TupleValue:
for (const TupleElement& field : t->GetTupleValue().elements) {
if (e->GetFieldAccessExpression().field == field.name) {
@@ -386,11 +369,10 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
return TCResult(new_e, field.value, res.types);
}
}
llvm::errs() << e->line_num << ": compilation error, struct "
<< t->GetStructType().name
<< " does not have a field named "
<< e->GetFieldAccessExpression().field << "\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num)
<< "struct " << t->GetStructType().name
<< " does not have a field named "
<< e->GetFieldAccessExpression().field;
case ValKind::ChoiceType:
for (auto vt = t->GetChoiceType().alternatives.begin();
vt != t->GetChoiceType().alternatives.end(); ++vt) {
@@ -401,18 +383,15 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
return TCResult(new_e, fun_ty, res.types);
}
}
llvm::errs() << e->line_num << ": compilation error, struct "
<< t->GetStructType().name
<< " does not have a field named "
<< e->GetFieldAccessExpression().field << "\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num)
<< "struct " << t->GetStructType().name
<< " does not have a field named "
<< e->GetFieldAccessExpression().field;
default:
llvm::errs()
<< e->line_num
<< ": compilation error in field access, expected a struct\n"
<< *e << "\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num)
<< "field access, expected a struct\n"
<< *e;
}
}
case ExpressionKind::IdentifierExpression: {
@@ -421,9 +400,8 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
if (type) {
return TCResult(e, *type, types);
} else {
llvm::errs() << e->line_num << ": could not find `"
<< e->GetIdentifierExpression().name << "`\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num)
<< "could not find `" << e->GetIdentifierExpression().name << "`";
}
}
case ExpressionKind::IntLiteral:
@@ -522,10 +500,9 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
return TCResult(new_e, return_type, arg_res.types);
}
default: {
llvm::errs() << e->line_num
<< ": compilation error in call, expected a function\n"
<< *e << "\n";
exit(-1);
FATAL_COMPILATION_ERROR(e->line_num)
<< "in call, expected a function\n"
<< *e;
}
}
break;
@@ -722,9 +699,8 @@ auto CheckOrEnsureReturn(const Statement* stmt, bool void_return, int line_num)
return Statement::MakeReturn(line_num,
Expression::MakeTupleLiteral(line_num, {}));
} else {
llvm::errs()
<< "control-flow reaches end of non-void function without a return\n";
exit(-1);
FATAL_COMPILATION_ERROR(line_num)
<< "control-flow reaches end of non-void function without a return";
}
}
switch (stmt->tag()) {
@@ -778,11 +754,8 @@ auto CheckOrEnsureReturn(const Statement* stmt, bool void_return, int line_num)
Statement::MakeReturn(stmt->line_num, Expression::MakeTupleLiteral(
stmt->line_num, {})));
} else {
llvm::errs()
<< stmt->line_num
<< ": control-flow reaches end of non-void function without a "
"return\n";
exit(-1);
FATAL_COMPILATION_ERROR(stmt->line_num)
<< "control-flow reaches end of non-void function without a return";
}
}
}
@@ -972,8 +945,8 @@ auto TopLevel(std::list<Declaration>* fs) -> TypeCheckContext {
}
if (found_main == false) {
llvm::errs() << "error, program must contain a function named `main`\n";
exit(-1);
FATAL_COMPILATION_ERROR_NO_LINE()
<< "program must contain a function named `main`";
}
return tops;
}
+7 -9
View File
@@ -7,6 +7,7 @@
#include <algorithm>
#include "common/check.h"
#include "executable_semantics/common/error.h"
#include "llvm/ADT/StringExtras.h"
namespace Carbon {
@@ -264,24 +265,21 @@ auto GetMember(const Value* v, const std::string& f, int line_num)
const Value* field =
v->GetStructValue().inits->GetTupleValue().FindField(f);
if (field == nullptr) {
llvm::errs() << "runtime error, member " << f << " not in " << *v
<< "\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num) << "member " << f << " not in " << *v;
}
return field;
}
case ValKind::TupleValue: {
const Value* field = v->GetTupleValue().FindField(f);
if (field == nullptr) {
llvm::errs() << "field " << f << " not in " << *v << "\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num) << "field " << f << " not in " << *v;
}
return field;
}
case ValKind::ChoiceType: {
if (FindInVarValues(f, v->GetChoiceType().alternatives) == nullptr) {
llvm::errs() << "alternative " << f << " not in " << *v << "\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num)
<< "alternative " << f << " not in " << *v;
}
return Value::MakeAlternativeConstructorValue(f, v->GetChoiceType().name);
}
@@ -323,8 +321,8 @@ auto SetFieldImpl(const Value* value,
return element.name == *path_begin;
});
if (it == elements.end()) {
llvm::errs() << "field " << *path_begin << " not in " << *value << "\n";
exit(-1);
FATAL_RUNTIME_ERROR(line_num)
<< "field " << *path_begin << " not in " << *value;
}
it->value = SetFieldImpl(it->value, path_begin + 1, path_end, field_value,
line_num);
+2 -2
View File
@@ -23,8 +23,8 @@ auto parse(const std::string& input_file_name)
-> std::variant<AST, SyntaxErrorCode> {
yyin = fopen(input_file_name.c_str(), "r");
if (yyin == nullptr) {
FatalUserError() << "Error opening '" << input_file_name
<< "': " << std::strerror(errno);
FATAL_USER_ERROR_NO_LINE() << "Error opening '" << input_file_name
<< "': " << std::strerror(errno);
}
std::optional<AST> parsed_input = std::nullopt;
@@ -1,2 +1,2 @@
12: undefined behavior: access to dead value 1
RUNTIME ERROR: 12: : undefined behavior: access to dead value 1
EXIT CODE: 255
+1 -1
View File
@@ -1,2 +1,2 @@
10: compilation error, tuples of different length
COMPILATION ERROR: 10: tuples of different length
EXIT CODE: 255
@@ -1,4 +1,4 @@
ERROR: 10: type error in argument deduction
COMPILATION ERROR: 10: type error in argument deduction
expected: Int
actual: Bool
EXIT CODE: 255
@@ -1,4 +1,4 @@
ERROR: 6: type error in addition(1)
COMPILATION ERROR: 6: type error in addition(1)
expected: Int
actual: T
EXIT CODE: 255
+1 -1
View File
@@ -1,4 +1,4 @@
ERROR: 7: type error in initializer of variable
COMPILATION ERROR: 7: type error in initializer of variable
expected: Int
actual: Bool
EXIT CODE: 255
+1 -1
View File
@@ -1,4 +1,4 @@
ERROR: 10: type error in return
COMPILATION ERROR: 10: type error in return
expected: ()
actual: Int
EXIT CODE: 255
+1 -1
View File
@@ -1,2 +1,2 @@
8: could not find `y`
RUNTIME ERROR: 8: : could not find `y`
EXIT CODE: 255
+1 -1
View File
@@ -1,2 +1,2 @@
7: compilation error, pattern variables are only allowed in pattern context
COMPILATION ERROR: 7: pattern variables are only allowed in pattern context
EXIT CODE: 255
@@ -0,0 +1,12 @@
// 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
struct Point {
var x: Int;
var y: Int;
}
fn main() -> Int {
return Point(.x = 1, .y = 2).z - 1;
}
@@ -0,0 +1,2 @@
COMPILATION ERROR: 11: struct Point does not have a field named z
EXIT CODE: 255
@@ -0,0 +1,12 @@
// 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
struct Point {
var x: Int;
var y: Int;
}
fn main() -> Int {
return Point(.x = 1, .z = 2).x - 1;
}
@@ -0,0 +1,2 @@
COMPILATION ERROR: 11: field names do not match, expected y but got z
EXIT CODE: 255
@@ -0,0 +1,12 @@
// 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
struct Point {
var x: Int;
var y: Int;
}
fn main() -> Int {
return Point(.x = 1).x - 1;
}
@@ -0,0 +1,2 @@
COMPILATION ERROR: 11: tuples of different length
EXIT CODE: 255
+1 -1
View File
@@ -1,4 +1,4 @@
ERROR: 8: type error in pattern variable
COMPILATION ERROR: 8: type error in pattern variable
expected: (x = Int, y = Int)
actual: (y = Int, x = Int)
EXIT CODE: 255
+1 -1
View File
@@ -1,4 +1,4 @@
ERROR: 8: type error in ==
COMPILATION ERROR: 8: type error in ==
expected: (0 = Int, 1 = Int)
actual: (0 = Int)
EXIT CODE: 255