Replaced std::exit() with return Carbon::ErrorOr for expected errors like invalid syntax (#1120)

* Replaced std::exit() with return llvm::Expected/llvm::Error<T> for expected errors like invalid syntax.

* Use llvm::formatv() for formatting lexer error messages.
x

* Addresed merge errors.

* Fixed impl scope.

* Made ErrorBuilder::operator<< nodiscard, to catch code forgetting 'return' in 'return FATAL_COMPILATION_ERROR()'.

* FatalComplationError() -> ParseAndLexContext::RecordLexerError().
Other usages of ERROR_TOKEN in lexer.lpp were actually supposed to be END_OF_FILE.

* Update executable_semantics/syntax/parse_and_lex_context.h

Co-authored-by: Jon Meow <jperkins@google.com>

* Code review fixes.

* Update executable_semantics/syntax/parser.ypp

Co-authored-by: Jon Meow <jperkins@google.com>

* More code review fixes.

* Update executable_semantics/interpreter/type_checker.h

Co-authored-by: Jon Meow <jperkins@google.com>

* Yet more code review fixes...

* Update executable_semantics/syntax/lexer.lpp

Co-authored-by: Jon Meow <jperkins@google.com>

* code review comments

* Update executable_semantics/interpreter/interpreter.cpp

Co-authored-by: Geoff Romer <gromer@google.com>

* Apply suggestions from code review

Co-authored-by: Jon Meow <jperkins@google.com>

* Update executable_semantics/syntax/lexer.lpp

Co-authored-by: Jon Meow <jperkins@google.com>

* code review

* code review

* Apply suggestions from code review

Co-authored-by: Jon Meow <jperkins@google.com>

* formatted code

* review comments

* Switched to the new ErrorOr<V> error implementation

* code review comments

* fixed comment

* restored ostream.h as #976 makes the change unnecesary

* review comments

Co-authored-by: Jon Meow <jperkins@google.com>
Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
pk19604014
2022-03-22 16:17:04 -04:00
committed by GitHub
co-authored by Jon Meow Geoff Romer
parent e5a87af6fe
commit aa8a5f174d
43 changed files with 1324 additions and 873 deletions
+2
View File
@@ -203,8 +203,10 @@ cc_library(
":source_location",
":value_category",
"//common:check",
"//common:error",
"//executable_semantics/common:error",
"//executable_semantics/common:nonnull",
"@llvm-project//llvm:Support",
],
)
+20 -11
View File
@@ -112,29 +112,38 @@ void ReturnTerm::Print(llvm::raw_ostream& out) const {
}
}
// Look for the `me` parameter in the `deduced_parameters_`
// and put it in the `me_pattern_`.
void FunctionDeclaration::ResolveDeducedAndReceiver(
const std::vector<Nonnull<AstNode*>>& deduced_params) {
auto FunctionDeclaration::Create(
Nonnull<Arena*> arena, SourceLocation source_loc, std::string name,
std::vector<Nonnull<AstNode*>> deduced_params,
std::optional<Nonnull<BindingPattern*>> me_pattern,
Nonnull<TuplePattern*> param_pattern, ReturnTerm return_term,
std::optional<Nonnull<Block*>> body)
-> ErrorOr<Nonnull<FunctionDeclaration*>> {
std::vector<Nonnull<GenericBinding*>> resolved_params;
// Look for the `me` parameter in the `deduced_parameters`
// and put it in the `me_pattern`.
for (Nonnull<AstNode*> param : deduced_params) {
switch (param->kind()) {
case AstNodeKind::GenericBinding:
deduced_parameters_.push_back(&cast<GenericBinding>(*param));
resolved_params.push_back(&cast<GenericBinding>(*param));
break;
case AstNodeKind::BindingPattern: {
Nonnull<BindingPattern*> bp = &cast<BindingPattern>(*param);
if (me_pattern_.has_value() || bp->name() != "me") {
FATAL_COMPILATION_ERROR(source_loc())
<< "illegal binding pattern in implicit parameter list";
if (me_pattern.has_value() || bp->name() != "me") {
return FATAL_COMPILATION_ERROR(source_loc)
<< "illegal binding pattern in implicit parameter list";
}
me_pattern_ = bp;
me_pattern = bp;
break;
}
default:
FATAL_COMPILATION_ERROR(source_loc())
<< "illegal AST node in implicit parameter list";
return FATAL_COMPILATION_ERROR(source_loc)
<< "illegal AST node in implicit parameter list";
}
}
return arena->New<FunctionDeclaration>(source_loc, name, resolved_params,
me_pattern, param_pattern, return_term,
body);
}
void FunctionDeclaration::PrintDepth(int depth, llvm::raw_ostream& out) const {
+13 -5
View File
@@ -82,20 +82,29 @@ class FunctionDeclaration : public Declaration {
public:
using ImplementsCarbonValueNode = void;
static auto Create(Nonnull<Arena*> arena, SourceLocation source_loc,
std::string name,
std::vector<Nonnull<AstNode*>> deduced_params,
std::optional<Nonnull<BindingPattern*>> me_pattern,
Nonnull<TuplePattern*> param_pattern,
ReturnTerm return_term,
std::optional<Nonnull<Block*>> body)
-> ErrorOr<Nonnull<FunctionDeclaration*>>;
// Use `Create()` instead. This is public only so Arena::New() can call it.
FunctionDeclaration(SourceLocation source_loc, std::string name,
std::vector<Nonnull<AstNode*>> deduced_params,
std::vector<Nonnull<GenericBinding*>> deduced_params,
std::optional<Nonnull<BindingPattern*>> me_pattern,
Nonnull<TuplePattern*> param_pattern,
ReturnTerm return_term,
std::optional<Nonnull<Block*>> body)
: Declaration(AstNodeKind::FunctionDeclaration, source_loc),
name_(std::move(name)),
deduced_parameters_(std::move(deduced_params)),
me_pattern_(me_pattern),
param_pattern_(param_pattern),
return_term_(return_term),
body_(body) {
ResolveDeducedAndReceiver(deduced_params);
}
body_(body) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromFunctionDeclaration(node->kind());
@@ -135,7 +144,6 @@ class FunctionDeclaration : public Declaration {
auto is_method() const -> bool { return me_pattern_.has_value(); }
private:
void ResolveDeducedAndReceiver(const std::vector<Nonnull<AstNode*>>&);
std::string name_;
std::vector<Nonnull<GenericBinding*>> deduced_parameters_;
std::optional<Nonnull<BindingPattern*>> me_pattern_;
+3 -2
View File
@@ -20,13 +20,14 @@ using llvm::isa;
auto IntrinsicExpression::FindIntrinsic(std::string_view name,
SourceLocation source_loc)
-> Intrinsic {
-> ErrorOr<Intrinsic> {
static const auto& intrinsic_map =
*new std::map<std::string_view, Intrinsic>({{"print", Intrinsic::Print}});
name.remove_prefix(std::strlen("__intrinsic_"));
auto it = intrinsic_map.find(name);
if (it == intrinsic_map.end()) {
FATAL_COMPILATION_ERROR(source_loc) << "Unknown intrinsic '" << name << "'";
return FATAL_COMPILATION_ERROR(source_loc)
<< "Unknown intrinsic '" << name << "'";
}
return it->second;
}
+7 -8
View File
@@ -465,11 +465,15 @@ class IntrinsicExpression : public Expression {
Print,
};
explicit IntrinsicExpression(std::string_view intrinsic_name,
Nonnull<TupleLiteral*> args,
// Returns the enumerator corresponding to the intrinsic named `name`,
// or raises a fatal compile error if there is no such enumerator.
static auto FindIntrinsic(std::string_view name, SourceLocation source_loc)
-> ErrorOr<Intrinsic>;
explicit IntrinsicExpression(Intrinsic intrinsic, Nonnull<TupleLiteral*> args,
SourceLocation source_loc)
: Expression(AstNodeKind::IntrinsicExpression, source_loc),
intrinsic_(FindIntrinsic(intrinsic_name, source_loc)),
intrinsic_(intrinsic),
args_(args) {}
static auto classof(const AstNode* node) -> bool {
@@ -481,11 +485,6 @@ class IntrinsicExpression : public Expression {
auto args() -> TupleLiteral& { return *args_; }
private:
// Returns the enumerator corresponding to the intrinsic named `name`,
// or raises a fatal compile error if there is no such enumerator.
static auto FindIntrinsic(std::string_view name, SourceLocation source_loc)
-> Intrinsic;
Intrinsic intrinsic_;
Nonnull<TupleLiteral*> args_;
};
+5 -13
View File
@@ -108,23 +108,15 @@ auto TuplePatternFromParenContents(Nonnull<Arena*> arena,
// Used by AlternativePattern for constructor initialization. Produces a helpful
// error for incorrect expressions, rather than letting a default cast error
// apply.
static auto RequireFieldAccess(Nonnull<Expression*> alternative)
-> FieldAccessExpression& {
auto AlternativePattern::RequireFieldAccess(Nonnull<Expression*> alternative)
-> ErrorOr<Nonnull<FieldAccessExpression*>> {
if (alternative->kind() != ExpressionKind::FieldAccessExpression) {
FATAL_PROGRAM_ERROR(alternative->source_loc())
<< "Alternative pattern must have the form of a field access.";
return FATAL_PROGRAM_ERROR(alternative->source_loc())
<< "Alternative pattern must have the form of a field access.";
}
return cast<FieldAccessExpression>(*alternative);
return &cast<FieldAccessExpression>(*alternative);
}
AlternativePattern::AlternativePattern(SourceLocation source_loc,
Nonnull<Expression*> alternative,
Nonnull<TuplePattern*> arguments)
: Pattern(AstNodeKind::AlternativePattern, source_loc),
choice_type_(&RequireFieldAccess(alternative).aggregate()),
alternative_name_(RequireFieldAccess(alternative).field()),
arguments_(arguments) {}
auto ParenExpressionToParenPattern(Nonnull<Arena*> arena,
const ParenContents<Expression>& contents)
-> ParenContents<Pattern> {
+16 -6
View File
@@ -218,6 +218,19 @@ auto ParenExpressionToParenPattern(Nonnull<Arena*> arena,
// A pattern that matches an alternative of a choice type.
class AlternativePattern : public Pattern {
public:
// Constructs an AlternativePattern that matches the alternative specified
// by `alternative`, if its arguments match `arguments`.
static auto Create(Nonnull<Arena*> arena, SourceLocation source_loc,
Nonnull<Expression*> alternative,
Nonnull<TuplePattern*> arguments)
-> ErrorOr<Nonnull<AlternativePattern*>> {
ASSIGN_OR_RETURN(Nonnull<FieldAccessExpression*> field_access,
RequireFieldAccess(alternative));
return arena->New<AlternativePattern>(source_loc,
&field_access->aggregate(),
field_access->field(), arguments);
}
// Constructs an AlternativePattern that matches a value of the type
// specified by choice_type if it represents an alternative named
// alternative_name, and its arguments match `arguments`.
@@ -230,12 +243,6 @@ class AlternativePattern : public Pattern {
alternative_name_(std::move(alternative_name)),
arguments_(arguments) {}
// Constructs an AlternativePattern that matches the alternative specified
// by `alternative`, if its arguments match `arguments`.
AlternativePattern(SourceLocation source_loc,
Nonnull<Expression*> alternative,
Nonnull<TuplePattern*> arguments);
static auto classof(const AstNode* node) -> bool {
return InheritsFromAlternativePattern(node->kind());
}
@@ -249,6 +256,9 @@ class AlternativePattern : public Pattern {
auto arguments() -> TuplePattern& { return *arguments_; }
private:
static auto RequireFieldAccess(Nonnull<Expression*> alternative)
-> ErrorOr<Nonnull<FieldAccessExpression*>>;
Nonnull<Expression*> choice_type_;
std::string alternative_name_;
Nonnull<TuplePattern*> arguments_;
+22 -15
View File
@@ -5,43 +5,50 @@
#include "executable_semantics/ast/static_scope.h"
#include "executable_semantics/common/error.h"
#include "llvm/Support/Error.h"
namespace Carbon {
void StaticScope::Add(std::string name, ValueNodeView entity) {
auto StaticScope::Add(std::string name, ValueNodeView entity)
-> ErrorOr<Success> {
auto [it, success] = declared_names_.insert({name, entity});
if (!success && it->second != entity) {
FATAL_COMPILATION_ERROR(entity.base().source_loc())
<< "Duplicate name `" << name << "` also found at "
<< it->second.base().source_loc();
return FATAL_COMPILATION_ERROR(entity.base().source_loc())
<< "Duplicate name `" << name << "` also found at "
<< it->second.base().source_loc();
}
return Success();
}
auto StaticScope::Resolve(const std::string& name,
SourceLocation source_loc) const -> ValueNodeView {
std::optional<ValueNodeView> result = TryResolve(name, source_loc);
if (!result.has_value()) {
FATAL_COMPILATION_ERROR(source_loc) << "could not resolve '" << name << "'";
SourceLocation source_loc) const
-> ErrorOr<ValueNodeView> {
ASSIGN_OR_RETURN(std::optional<ValueNodeView> result,
TryResolve(name, source_loc));
if (!result) {
return FATAL_COMPILATION_ERROR(source_loc)
<< "could not resolve '" << name << "'";
}
return *result;
}
auto StaticScope::TryResolve(const std::string& name,
SourceLocation source_loc) const
-> std::optional<ValueNodeView> {
-> ErrorOr<std::optional<ValueNodeView>> {
auto it = declared_names_.find(name);
if (it != declared_names_.end()) {
return it->second;
return std::make_optional(it->second);
}
std::optional<ValueNodeView> result;
for (Nonnull<const StaticScope*> parent : parent_scopes_) {
auto parent_result = parent->TryResolve(name, source_loc);
ASSIGN_OR_RETURN(std::optional<ValueNodeView> parent_result,
parent->TryResolve(name, source_loc));
if (parent_result.has_value() && result.has_value() &&
*parent_result != *result) {
FATAL_COMPILATION_ERROR(source_loc)
<< "'" << name << "' is ambiguous between "
<< result->base().source_loc() << " and "
<< parent_result->base().source_loc();
return FATAL_COMPILATION_ERROR(source_loc)
<< "'" << name << "' is ambiguous between "
<< result->base().source_loc() << " and "
<< parent_result->base().source_loc();
}
result = parent_result;
}
+5 -3
View File
@@ -12,10 +12,12 @@
#include <vector>
#include "common/check.h"
#include "common/error.h"
#include "executable_semantics/ast/ast_node.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/ast/value_category.h"
#include "executable_semantics/common/nonnull.h"
#include "llvm/Support/Error.h"
namespace Carbon {
@@ -133,7 +135,7 @@ class StaticScope {
public:
// Defines `name` to be `entity` in this scope, or reports a compilation error
// if `name` is already defined to be a different entity in this scope.
void Add(std::string name, ValueNodeView entity);
auto Add(std::string name, ValueNodeView entity) -> ErrorOr<Success>;
// Make `parent` a parent of this scope.
// REQUIRES: `parent` is not already a parent of this scope.
@@ -145,14 +147,14 @@ class StaticScope {
// scope, or reports a compilation error at `source_loc` there isn't exactly
// one such definition.
auto Resolve(const std::string& name, SourceLocation source_loc) const
-> ValueNodeView;
-> ErrorOr<ValueNodeView>;
private:
// Equivalent to Resolve, but returns `nullopt` instead of raising an error
// if no definition can be found. Still raises a compilation error if more
// than one definition is found.
auto TryResolve(const std::string& name, SourceLocation source_loc) const
-> std::optional<ValueNodeView>;
-> ErrorOr<std::optional<ValueNodeView>>;
// Maps locally declared names to their entities.
std::unordered_map<std::string, ValueNodeView> declared_names_;