diff --git a/executable_semantics/ast/BUILD b/executable_semantics/ast/BUILD index 84d1d798558e..5dbec58e75a2 100644 --- a/executable_semantics/ast/BUILD +++ b/executable_semantics/ast/BUILD @@ -4,6 +4,17 @@ package(default_visibility = ["//executable_semantics:__subpackages__"]) +cc_library( + name = "class_definition", + hdrs = ["class_definition.h"], + deps = [ + ":member", + ":source_location", + "//common:ostream", + "@llvm-project//llvm:Support", + ], +) + cc_library( name = "declaration", srcs = ["declaration.cpp"], @@ -16,6 +27,7 @@ cc_library( ":function_definition", ":member", ":pattern", + ":source_location", "//common:ostream", "//executable_semantics/common:ptr", "@llvm-project//llvm:Support", @@ -53,6 +65,7 @@ cc_library( hdrs = ["function_definition.h"], deps = [ ":expression", + ":source_location", ":statement", "@llvm-project//llvm:Support", ], @@ -64,6 +77,7 @@ cc_library( hdrs = ["member.h"], deps = [ ":pattern", + ":source_location", "//common:ostream", ], ) @@ -71,6 +85,10 @@ cc_library( cc_library( name = "paren_contents", hdrs = ["paren_contents.h"], + deps = [ + ":source_location", + "//executable_semantics/common:error", + ], ) cc_library( @@ -79,6 +97,7 @@ cc_library( hdrs = ["pattern.h"], deps = [ ":expression", + ":source_location", "//common:ostream", "//executable_semantics/common:arena", "//executable_semantics/common:error", @@ -98,6 +117,12 @@ cc_test( ], ) +cc_library( + name = "source_location", + hdrs = ["source_location.h"], + deps = ["//common:ostream"], +) + cc_library( name = "statement", srcs = ["statement.cpp"], @@ -105,19 +130,10 @@ cc_library( deps = [ ":expression", ":pattern", + ":source_location", "//common:check", "//common:ostream", "//executable_semantics/common:arena", "@llvm-project//llvm:Support", ], ) - -cc_library( - name = "class_definition", - hdrs = ["class_definition.h"], - deps = [ - ":member", - "//common:ostream", - "@llvm-project//llvm:Support", - ], -) diff --git a/executable_semantics/ast/class_definition.h b/executable_semantics/ast/class_definition.h index dcac975363b0..c65fd640dfb2 100644 --- a/executable_semantics/ast/class_definition.h +++ b/executable_semantics/ast/class_definition.h @@ -2,22 +2,23 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef EXECUTABLE_SEMANTICS_AST_STRUCT_DEFINITION_H_ -#define EXECUTABLE_SEMANTICS_AST_STRUCT_DEFINITION_H_ +#ifndef EXECUTABLE_SEMANTICS_AST_CLASS_DEFINITION_H_ +#define EXECUTABLE_SEMANTICS_AST_CLASS_DEFINITION_H_ #include #include #include "executable_semantics/ast/member.h" +#include "executable_semantics/ast/source_location.h" namespace Carbon { struct ClassDefinition { - int line_num; + SourceLocation loc; std::string name; std::list members; }; } // namespace Carbon -#endif // EXECUTABLE_SEMANTICS_AST_STRUCT_DEFINITION_H_ +#endif // EXECUTABLE_SEMANTICS_AST_CLASS_DEFINITION_H_ diff --git a/executable_semantics/ast/declaration.h b/executable_semantics/ast/declaration.h index 3acf1d030e21..6dca09e2d6f9 100644 --- a/executable_semantics/ast/declaration.h +++ b/executable_semantics/ast/declaration.h @@ -13,6 +13,7 @@ #include "executable_semantics/ast/function_definition.h" #include "executable_semantics/ast/member.h" #include "executable_semantics/ast/pattern.h" +#include "executable_semantics/ast/source_location.h" #include "executable_semantics/common/ptr.h" #include "llvm/Support/Compiler.h" @@ -42,7 +43,7 @@ class Declaration { // object. auto Tag() const -> Kind { return tag; } - auto LineNumber() const -> int { return line_num; } + auto SourceLoc() const -> SourceLocation { return loc; } void Print(llvm::raw_ostream& out) const; @@ -50,17 +51,17 @@ class Declaration { // Constructs a Declaration representing syntax at the given line number. // `tag` must be the enumerator corresponding to the most-derived type being // constructed. - Declaration(Kind tag, int line_num) : tag(tag), line_num(line_num) {} + Declaration(Kind tag, SourceLocation loc) : tag(tag), loc(loc) {} private: const Kind tag; - int line_num; + SourceLocation loc; }; class FunctionDeclaration : public Declaration { public: FunctionDeclaration(Ptr definition) - : Declaration(Kind::FunctionDeclaration, definition->line_num), + : Declaration(Kind::FunctionDeclaration, definition->source_location), definition(definition) {} static auto classof(const Declaration* decl) -> bool { @@ -75,9 +76,10 @@ class FunctionDeclaration : public Declaration { class ClassDeclaration : public Declaration { public: - ClassDeclaration(int line_num, std::string name, std::list members) - : Declaration(Kind::ClassDeclaration, line_num), - definition({.line_num = line_num, + ClassDeclaration(SourceLocation loc, std::string name, + std::list members) + : Declaration(Kind::ClassDeclaration, loc), + definition({.loc = loc, .name = std::move(name), .members = std::move(members)}) {} @@ -94,9 +96,9 @@ class ClassDeclaration : public Declaration { class ChoiceDeclaration : public Declaration { public: ChoiceDeclaration( - int line_num, std::string name, + SourceLocation loc, std::string name, std::list> alternatives) - : Declaration(Kind::ChoiceDeclaration, line_num), + : Declaration(Kind::ChoiceDeclaration, loc), name(std::move(name)), alternatives(std::move(alternatives)) {} @@ -118,9 +120,9 @@ class ChoiceDeclaration : public Declaration { // Global variable definition implements the Declaration concept. class VariableDeclaration : public Declaration { public: - VariableDeclaration(int line_num, const BindingPattern* binding, + VariableDeclaration(SourceLocation loc, const BindingPattern* binding, const Expression* initializer) - : Declaration(Kind::VariableDeclaration, line_num), + : Declaration(Kind::VariableDeclaration, loc), binding(binding), initializer(initializer) {} diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index ddb8f838d425..5652b50a3b07 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -17,21 +17,21 @@ namespace Carbon { using llvm::cast; auto ExpressionFromParenContents( - int line_num, const ParenContents& paren_contents) + SourceLocation loc, const ParenContents& paren_contents) -> const Expression* { std::optional single_term = paren_contents.SingleTerm(); if (single_term.has_value()) { return *single_term; } else { - return TupleExpressionFromParenContents(line_num, paren_contents); + return TupleExpressionFromParenContents(loc, paren_contents); } } auto TupleExpressionFromParenContents( - int line_num, const ParenContents& paren_contents) + SourceLocation loc, const ParenContents& paren_contents) -> const Expression* { return global_arena->RawNew( - line_num, paren_contents.TupleElements(line_num)); + loc, paren_contents.TupleElements(loc)); } static void PrintOp(llvm::raw_ostream& out, Operator op) { diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index 0c18a7c2adef..696a122eb3e5 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -12,6 +12,7 @@ #include "common/ostream.h" #include "executable_semantics/ast/paren_contents.h" +#include "executable_semantics/ast/source_location.h" #include "llvm/Support/Compiler.h" namespace Carbon { @@ -41,7 +42,7 @@ class Expression { // object. auto Tag() const -> Kind { return tag; } - auto LineNumber() const -> int { return line_num; } + auto SourceLoc() const -> SourceLocation { return loc; } void Print(llvm::raw_ostream& out) const; LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); } @@ -50,24 +51,24 @@ class Expression { // Constructs an Expression representing syntax at the given line number. // `tag` must be the enumerator corresponding to the most-derived type being // constructed. - Expression(Kind tag, int line_num) : tag(tag), line_num(line_num) {} + Expression(Kind tag, SourceLocation loc) : tag(tag), loc(loc) {} private: const Kind tag; - int line_num; + SourceLocation loc; }; // Converts paren_contents to an Expression, interpreting the parentheses as // grouping if their contents permit that interpretation, or as forming a // tuple otherwise. auto ExpressionFromParenContents( - int line_num, const ParenContents& paren_contents) + SourceLocation loc, const ParenContents& paren_contents) -> const Expression*; // Converts paren_contents to an Expression, interpreting the parentheses as // forming a tuple. auto TupleExpressionFromParenContents( - int line_num, const ParenContents& paren_contents) + SourceLocation loc, const ParenContents& paren_contents) -> const Expression*; // A FieldInitializer represents the initialization of a single tuple field. @@ -97,9 +98,8 @@ enum class Operator { class IdentifierExpression : public Expression { public: - explicit IdentifierExpression(int line_num, std::string name) - : Expression(Kind::IdentifierExpression, line_num), - name(std::move(name)) {} + explicit IdentifierExpression(SourceLocation loc, std::string name) + : Expression(Kind::IdentifierExpression, loc), name(std::move(name)) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::IdentifierExpression; @@ -113,9 +113,9 @@ class IdentifierExpression : public Expression { class FieldAccessExpression : public Expression { public: - explicit FieldAccessExpression(int line_num, const Expression* aggregate, - std::string field) - : Expression(Kind::FieldAccessExpression, line_num), + explicit FieldAccessExpression(SourceLocation loc, + const Expression* aggregate, std::string field) + : Expression(Kind::FieldAccessExpression, loc), aggregate(aggregate), field(std::move(field)) {} @@ -133,9 +133,9 @@ class FieldAccessExpression : public Expression { class IndexExpression : public Expression { public: - explicit IndexExpression(int line_num, const Expression* aggregate, + explicit IndexExpression(SourceLocation loc, const Expression* aggregate, const Expression* offset) - : Expression(Kind::IndexExpression, line_num), + : Expression(Kind::IndexExpression, loc), aggregate(aggregate), offset(offset) {} @@ -153,8 +153,8 @@ class IndexExpression : public Expression { class IntLiteral : public Expression { public: - explicit IntLiteral(int line_num, int val) - : Expression(Kind::IntLiteral, line_num), val(val) {} + explicit IntLiteral(SourceLocation loc, int val) + : Expression(Kind::IntLiteral, loc), val(val) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::IntLiteral; @@ -168,8 +168,8 @@ class IntLiteral : public Expression { class BoolLiteral : public Expression { public: - explicit BoolLiteral(int line_num, bool val) - : Expression(Kind::BoolLiteral, line_num), val(val) {} + explicit BoolLiteral(SourceLocation loc, bool val) + : Expression(Kind::BoolLiteral, loc), val(val) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::BoolLiteral; @@ -183,8 +183,8 @@ class BoolLiteral : public Expression { class StringLiteral : public Expression { public: - explicit StringLiteral(int line_num, std::string val) - : Expression(Kind::StringLiteral, line_num), val(std::move(val)) {} + explicit StringLiteral(SourceLocation loc, std::string val) + : Expression(Kind::StringLiteral, loc), val(std::move(val)) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::StringLiteral; @@ -198,8 +198,8 @@ class StringLiteral : public Expression { class StringTypeLiteral : public Expression { public: - explicit StringTypeLiteral(int line_num) - : Expression(Kind::StringTypeLiteral, line_num) {} + explicit StringTypeLiteral(SourceLocation loc) + : Expression(Kind::StringTypeLiteral, loc) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::StringTypeLiteral; @@ -208,10 +208,11 @@ class StringTypeLiteral : public Expression { class TupleLiteral : public Expression { public: - explicit TupleLiteral(int line_num) : TupleLiteral(line_num, {}) {} + explicit TupleLiteral(SourceLocation loc) : TupleLiteral(loc, {}) {} - explicit TupleLiteral(int line_num, std::vector fields) - : Expression(Kind::TupleLiteral, line_num), fields(std::move(fields)) {} + explicit TupleLiteral(SourceLocation loc, + std::vector fields) + : Expression(Kind::TupleLiteral, loc), fields(std::move(fields)) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::TupleLiteral; @@ -225,9 +226,9 @@ class TupleLiteral : public Expression { class PrimitiveOperatorExpression : public Expression { public: - explicit PrimitiveOperatorExpression(int line_num, Operator op, + explicit PrimitiveOperatorExpression(SourceLocation loc, Operator op, std::vector arguments) - : Expression(Kind::PrimitiveOperatorExpression, line_num), + : Expression(Kind::PrimitiveOperatorExpression, loc), op(op), arguments(std::move(arguments)) {} @@ -247,9 +248,9 @@ class PrimitiveOperatorExpression : public Expression { class CallExpression : public Expression { public: - explicit CallExpression(int line_num, const Expression* function, + explicit CallExpression(SourceLocation loc, const Expression* function, const Expression* argument) - : Expression(Kind::CallExpression, line_num), + : Expression(Kind::CallExpression, loc), function(function), argument(argument) {} @@ -267,10 +268,10 @@ class CallExpression : public Expression { class FunctionTypeLiteral : public Expression { public: - explicit FunctionTypeLiteral(int line_num, const Expression* parameter, + explicit FunctionTypeLiteral(SourceLocation loc, const Expression* parameter, const Expression* return_type, bool is_omitted_return_type) - : Expression(Kind::FunctionTypeLiteral, line_num), + : Expression(Kind::FunctionTypeLiteral, loc), parameter(parameter), return_type(return_type), is_omitted_return_type(is_omitted_return_type) {} @@ -291,8 +292,8 @@ class FunctionTypeLiteral : public Expression { class BoolTypeLiteral : public Expression { public: - explicit BoolTypeLiteral(int line_num) - : Expression(Kind::BoolTypeLiteral, line_num) {} + explicit BoolTypeLiteral(SourceLocation loc) + : Expression(Kind::BoolTypeLiteral, loc) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::BoolTypeLiteral; @@ -301,8 +302,8 @@ class BoolTypeLiteral : public Expression { class IntTypeLiteral : public Expression { public: - explicit IntTypeLiteral(int line_num) - : Expression(Kind::IntTypeLiteral, line_num) {} + explicit IntTypeLiteral(SourceLocation loc) + : Expression(Kind::IntTypeLiteral, loc) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::IntTypeLiteral; @@ -311,8 +312,8 @@ class IntTypeLiteral : public Expression { class ContinuationTypeLiteral : public Expression { public: - explicit ContinuationTypeLiteral(int line_num) - : Expression(Kind::ContinuationTypeLiteral, line_num) {} + explicit ContinuationTypeLiteral(SourceLocation loc) + : Expression(Kind::ContinuationTypeLiteral, loc) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::ContinuationTypeLiteral; @@ -321,8 +322,8 @@ class ContinuationTypeLiteral : public Expression { class TypeTypeLiteral : public Expression { public: - explicit TypeTypeLiteral(int line_num) - : Expression(Kind::TypeTypeLiteral, line_num) {} + explicit TypeTypeLiteral(SourceLocation loc) + : Expression(Kind::TypeTypeLiteral, loc) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::TypeTypeLiteral; @@ -336,7 +337,8 @@ class IntrinsicExpression : public Expression { }; explicit IntrinsicExpression(IntrinsicKind intrinsic) - : Expression(Kind::IntrinsicExpression, -1), intrinsic(intrinsic) {} + : Expression(Kind::IntrinsicExpression, SourceLocation("", 0)), + intrinsic(intrinsic) {} static auto classof(const Expression* exp) -> bool { return exp->Tag() == Kind::IntrinsicExpression; diff --git a/executable_semantics/ast/expression_test.cpp b/executable_semantics/ast/expression_test.cpp index a404484968be..d817edbc3d5f 100644 --- a/executable_semantics/ast/expression_test.cpp +++ b/executable_semantics/ast/expression_test.cpp @@ -26,12 +26,16 @@ MATCHER_P(IntFieldNamed, name, "") { arg.expression->Tag() == Expression::Kind::IntLiteral; } +static auto FakeSourceLoc(int line_num) -> SourceLocation { + return SourceLocation("", line_num); +} + TEST(ExpressionTest, EmptyAsExpression) { ParenContents contents = {.elements = {}, .has_trailing_comma = false}; const Expression* expression = - ExpressionFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(expression->LineNumber(), 1); + ExpressionFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*expression).Fields(), IsEmpty()); } @@ -40,8 +44,8 @@ TEST(ExpressionTest, EmptyAsTuple) { ParenContents contents = {.elements = {}, .has_trailing_comma = false}; const Expression* tuple = - TupleExpressionFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(tuple->LineNumber(), 1); + TupleExpressionFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*tuple).Fields(), IsEmpty()); } @@ -55,26 +59,26 @@ TEST(ExpressionTest, UnaryNoCommaAsExpression) { // ``` ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->RawNew(/*line_num=*/2, 42)}}, + .term = global_arena->RawNew(FakeSourceLoc(2), + 42)}}, .has_trailing_comma = false}; const Expression* expression = - ExpressionFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(expression->LineNumber(), 2); + ExpressionFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(2)); ASSERT_EQ(expression->Tag(), Expression::Kind::IntLiteral); } TEST(ExpressionTest, UnaryNoCommaAsTuple) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->RawNew(/*line_num=*/2, 42)}}, + .term = global_arena->RawNew(FakeSourceLoc(2), + 42)}}, .has_trailing_comma = false}; const Expression* tuple = - TupleExpressionFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(tuple->LineNumber(), 1); + TupleExpressionFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*tuple).Fields(), ElementsAre(IntFieldNamed("0"))); @@ -83,13 +87,13 @@ TEST(ExpressionTest, UnaryNoCommaAsTuple) { TEST(ExpressionTest, UnaryWithCommaAsExpression) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->RawNew(/*line_num=*/2, 42)}}, + .term = global_arena->RawNew(FakeSourceLoc(2), + 42)}}, .has_trailing_comma = true}; const Expression* expression = - ExpressionFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(expression->LineNumber(), 1); + ExpressionFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*expression).Fields(), ElementsAre(IntFieldNamed("0"))); @@ -98,13 +102,13 @@ TEST(ExpressionTest, UnaryWithCommaAsExpression) { TEST(ExpressionTest, UnaryWithCommaAsTuple) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->RawNew(/*line_num=*/2, 42)}}, + .term = global_arena->RawNew(FakeSourceLoc(2), + 42)}}, .has_trailing_comma = true}; const Expression* tuple = - TupleExpressionFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(tuple->LineNumber(), 1); + TupleExpressionFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*tuple).Fields(), ElementsAre(IntFieldNamed("0"))); @@ -114,15 +118,15 @@ TEST(ExpressionTest, BinaryAsExpression) { ParenContents contents = { .elements = {{.name = std::nullopt, .term = - global_arena->RawNew(/*line_num=*/2, 42)}, + global_arena->RawNew(FakeSourceLoc(2), 42)}, {.name = std::nullopt, - .term = - global_arena->RawNew(/*line_num=*/3, 42)}}, + .term = global_arena->RawNew(FakeSourceLoc(3), + 42)}}, .has_trailing_comma = true}; const Expression* expression = - ExpressionFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(expression->LineNumber(), 1); + ExpressionFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*expression).Fields(), ElementsAre(IntFieldNamed("0"), IntFieldNamed("1"))); @@ -132,15 +136,15 @@ TEST(ExpressionTest, BinaryAsTuple) { ParenContents contents = { .elements = {{.name = std::nullopt, .term = - global_arena->RawNew(/*line_num=*/2, 42)}, + global_arena->RawNew(FakeSourceLoc(2), 42)}, {.name = std::nullopt, - .term = - global_arena->RawNew(/*line_num=*/3, 42)}}, + .term = global_arena->RawNew(FakeSourceLoc(3), + 42)}}, .has_trailing_comma = true}; const Expression* tuple = - TupleExpressionFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(tuple->LineNumber(), 1); + TupleExpressionFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*tuple).Fields(), ElementsAre(IntFieldNamed("0"), IntFieldNamed("1"))); diff --git a/executable_semantics/ast/function_definition.h b/executable_semantics/ast/function_definition.h index 4bc8daae76ea..970dd55a902c 100644 --- a/executable_semantics/ast/function_definition.h +++ b/executable_semantics/ast/function_definition.h @@ -8,6 +8,7 @@ #include "common/ostream.h" #include "executable_semantics/ast/expression.h" #include "executable_semantics/ast/pattern.h" +#include "executable_semantics/ast/source_location.h" #include "executable_semantics/ast/statement.h" #include "llvm/Support/Compiler.h" @@ -21,12 +22,12 @@ struct GenericBinding { }; struct FunctionDefinition { - FunctionDefinition(int line_num, std::string name, + FunctionDefinition(SourceLocation source_location, std::string name, std::vector deduced_params, const TuplePattern* param_pattern, const Pattern* return_type, bool is_omitted_return_type, const Statement* body) - : line_num(line_num), + : source_location(source_location), name(std::move(name)), deduced_parameters(deduced_params), param_pattern(param_pattern), @@ -38,7 +39,7 @@ struct FunctionDefinition { void PrintDepth(int depth, llvm::raw_ostream& out) const; LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); } - int line_num; + SourceLocation source_location; std::string name; std::vector deduced_parameters; const TuplePattern* param_pattern; diff --git a/executable_semantics/ast/member.h b/executable_semantics/ast/member.h index e629c14dd8bc..db3616eceb6d 100644 --- a/executable_semantics/ast/member.h +++ b/executable_semantics/ast/member.h @@ -10,6 +10,7 @@ #include "common/ostream.h" #include "executable_semantics/ast/expression.h" #include "executable_semantics/ast/pattern.h" +#include "executable_semantics/ast/source_location.h" #include "llvm/Support/Compiler.h" namespace Carbon { @@ -33,7 +34,7 @@ class Member { // object. auto Tag() const -> Kind { return tag; } - auto LineNumber() const -> int { return line_num; } + auto SourceLoc() const -> SourceLocation { return loc; } void Print(llvm::raw_ostream& out) const; @@ -41,17 +42,17 @@ class Member { // Constructs a Member representing syntax at the given line number. // `tag` must be the enumerator corresponding to the most-derived type being // constructed. - Member(Kind tag, int line_num) : tag(tag), line_num(line_num) {} + Member(Kind tag, SourceLocation loc) : tag(tag), loc(loc) {} private: const Kind tag; - int line_num; + SourceLocation loc; }; class FieldMember : public Member { public: - FieldMember(int line_num, const BindingPattern* binding) - : Member(Kind::FieldMember, line_num), binding(binding) {} + FieldMember(SourceLocation loc, const BindingPattern* binding) + : Member(Kind::FieldMember, loc), binding(binding) {} static auto classof(const Member* member) -> bool { return member->Tag() == Kind::FieldMember; diff --git a/executable_semantics/ast/paren_contents.h b/executable_semantics/ast/paren_contents.h index cb85c20a3455..9955ad3ec8a1 100644 --- a/executable_semantics/ast/paren_contents.h +++ b/executable_semantics/ast/paren_contents.h @@ -9,6 +9,7 @@ #include #include +#include "executable_semantics/ast/source_location.h" #include "executable_semantics/common/error.h" namespace Carbon { @@ -40,7 +41,7 @@ struct ParenContents { // // TODO: Find a way to deduce TupleElement from Term. template - auto TupleElements(int line_num) const -> std::vector; + auto TupleElements(SourceLocation loc) const -> std::vector; std::vector elements; bool has_trailing_comma; @@ -60,7 +61,7 @@ auto ParenContents::SingleTerm() const -> std::optional { template template -auto ParenContents::TupleElements(int line_num) const +auto ParenContents::TupleElements(SourceLocation loc) const -> std::vector { std::vector result; int i = 0; @@ -71,7 +72,7 @@ auto ParenContents::TupleElements(int line_num) const result.push_back(TupleElement(*element.name, element.term)); } else { if (seen_named_member) { - FATAL_PROGRAM_ERROR(line_num) + FATAL_PROGRAM_ERROR(loc) << "positional members must come before named members"; } result.push_back(TupleElement(std::to_string(i), element.term)); diff --git a/executable_semantics/ast/pattern.cpp b/executable_semantics/ast/pattern.cpp index 4c3b99902450..3bf1b6e0a9e6 100644 --- a/executable_semantics/ast/pattern.cpp +++ b/executable_semantics/ast/pattern.cpp @@ -55,7 +55,7 @@ void Pattern::Print(llvm::raw_ostream& out) const { } TuplePattern::TuplePattern(const Expression* tuple_literal) - : Pattern(Kind::TuplePattern, tuple_literal->LineNumber()) { + : Pattern(Kind::TuplePattern, tuple_literal->SourceLoc()) { const auto& tuple = cast(*tuple_literal); for (const FieldInitializer& init : tuple.Fields()) { fields.push_back(Field( @@ -63,30 +63,30 @@ TuplePattern::TuplePattern(const Expression* tuple_literal) } } -auto PatternFromParenContents(int line_num, +auto PatternFromParenContents(SourceLocation loc, const ParenContents& paren_contents) -> const Pattern* { std::optional single_term = paren_contents.SingleTerm(); if (single_term.has_value()) { return *single_term; } else { - return TuplePatternFromParenContents(line_num, paren_contents); + return TuplePatternFromParenContents(loc, paren_contents); } } -auto TuplePatternFromParenContents(int line_num, +auto TuplePatternFromParenContents(SourceLocation loc, const ParenContents& paren_contents) -> const TuplePattern* { return global_arena->RawNew( - line_num, paren_contents.TupleElements(line_num)); + loc, paren_contents.TupleElements(loc)); } -AlternativePattern::AlternativePattern(int line_num, +AlternativePattern::AlternativePattern(SourceLocation loc, const Expression* alternative, const TuplePattern* arguments) - : Pattern(Kind::AlternativePattern, line_num), arguments(arguments) { + : Pattern(Kind::AlternativePattern, loc), arguments(arguments) { if (alternative->Tag() != Expression::Kind::FieldAccessExpression) { - FATAL_PROGRAM_ERROR(alternative->LineNumber()) + FATAL_PROGRAM_ERROR(alternative->SourceLoc()) << "Alternative pattern must have the form of a field access."; } const auto& field_access = cast(*alternative); diff --git a/executable_semantics/ast/pattern.h b/executable_semantics/ast/pattern.h index d1e0807b24f9..36d721c26afb 100644 --- a/executable_semantics/ast/pattern.h +++ b/executable_semantics/ast/pattern.h @@ -11,6 +11,7 @@ #include "common/ostream.h" #include "executable_semantics/ast/expression.h" +#include "executable_semantics/ast/source_location.h" namespace Carbon { @@ -39,7 +40,7 @@ class Pattern { // object. auto Tag() const -> Kind { return tag; } - auto LineNumber() const -> int { return line_num; } + auto SourceLoc() const -> SourceLocation { return loc; } void Print(llvm::raw_ostream& out) const; LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); } @@ -48,17 +49,17 @@ class Pattern { // Constructs a Pattern representing syntax at the given line number. // `tag` must be the enumerator corresponding to the most-derived type being // constructed. - Pattern(Kind tag, int line_num) : tag(tag), line_num(line_num) {} + Pattern(Kind tag, SourceLocation loc) : tag(tag), loc(loc) {} private: const Kind tag; - int line_num; + SourceLocation loc; }; // A pattern consisting of the `auto` keyword. class AutoPattern : public Pattern { public: - explicit AutoPattern(int line_num) : Pattern(Kind::AutoPattern, line_num) {} + explicit AutoPattern(SourceLocation loc) : Pattern(Kind::AutoPattern, loc) {} static auto classof(const Pattern* pattern) -> bool { return pattern->Tag() == Kind::AutoPattern; @@ -69,11 +70,9 @@ class AutoPattern : public Pattern { // a name to it. class BindingPattern : public Pattern { public: - BindingPattern(int line_num, std::optional name, + BindingPattern(SourceLocation loc, std::optional name, const Pattern* type) - : Pattern(Kind::BindingPattern, line_num), - name(std::move(name)), - type(type) {} + : Pattern(Kind::BindingPattern, loc), name(std::move(name)), type(type) {} static auto classof(const Pattern* pattern) -> bool { return pattern->Tag() == Kind::BindingPattern; @@ -105,8 +104,8 @@ class TuplePattern : public Pattern { const Pattern* pattern; }; - TuplePattern(int line_num, std::vector fields) - : Pattern(Kind::TuplePattern, line_num), fields(std::move(fields)) {} + TuplePattern(SourceLocation loc, std::vector fields) + : Pattern(Kind::TuplePattern, loc), fields(std::move(fields)) {} // Converts tuple_literal to a TuplePattern, by wrapping each field in an // ExpressionPattern. @@ -127,13 +126,13 @@ class TuplePattern : public Pattern { // Converts paren_contents to a Pattern, interpreting the parentheses as // grouping if their contents permit that interpretation, or as forming a // tuple otherwise. -auto PatternFromParenContents(int line_num, +auto PatternFromParenContents(SourceLocation loc, const ParenContents& paren_contents) -> const Pattern*; // Converts paren_contents to a TuplePattern, interpreting the parentheses as // forming a tuple. -auto TuplePatternFromParenContents(int line_num, +auto TuplePatternFromParenContents(SourceLocation loc, const ParenContents& paren_contents) -> const TuplePattern*; @@ -148,17 +147,17 @@ class AlternativePattern : public Pattern { // 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`. - AlternativePattern(int line_num, const Expression* choice_type, + AlternativePattern(SourceLocation loc, const Expression* choice_type, std::string alternative_name, const TuplePattern* arguments) - : Pattern(Kind::AlternativePattern, line_num), + : Pattern(Kind::AlternativePattern, loc), choice_type(choice_type), alternative_name(std::move(alternative_name)), arguments(arguments) {} // Constructs an AlternativePattern that matches the alternative specified // by `alternative`, if its arguments match `arguments`. - AlternativePattern(int line_num, const Expression* alternative, + AlternativePattern(SourceLocation loc, const Expression* alternative, const TuplePattern* arguments); static auto classof(const Pattern* pattern) -> bool { @@ -182,7 +181,7 @@ class AlternativePattern : public Pattern { class ExpressionPattern : public Pattern { public: ExpressionPattern(const Expression* expression) - : Pattern(Kind::ExpressionPattern, expression->LineNumber()), + : Pattern(Kind::ExpressionPattern, expression->SourceLoc()), expression(expression) {} static auto classof(const Pattern* pattern) -> bool { diff --git a/executable_semantics/ast/pattern_test.cpp b/executable_semantics/ast/pattern_test.cpp index ff6e74fbd741..513f5b6e0b76 100644 --- a/executable_semantics/ast/pattern_test.cpp +++ b/executable_semantics/ast/pattern_test.cpp @@ -25,11 +25,15 @@ MATCHER_P(AutoFieldNamed, name, "") { return arg.name == std::string(name) && isa(arg.pattern); } +static auto FakeSourceLoc(int line_num) -> SourceLocation { + return SourceLocation("", line_num); +} + TEST(PatternTest, EmptyAsPattern) { ParenContents contents = {.elements = {}, .has_trailing_comma = false}; - const Pattern* pattern = PatternFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(pattern->LineNumber(), 1); + const Pattern* pattern = PatternFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(1)); ASSERT_TRUE(isa(pattern)); EXPECT_THAT(cast(pattern)->Fields(), IsEmpty()); } @@ -38,8 +42,8 @@ TEST(PatternTest, EmptyAsTuplePattern) { ParenContents contents = {.elements = {}, .has_trailing_comma = false}; const TuplePattern* tuple = - TuplePatternFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(tuple->LineNumber(), 1); + TuplePatternFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); EXPECT_THAT(tuple->Fields(), IsEmpty()); } @@ -52,34 +56,37 @@ TEST(PatternTest, UnaryNoCommaAsPattern) { // ``` ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->RawNew(/*line_num=*/2)}}, + .term = + global_arena->RawNew(FakeSourceLoc(2))}}, .has_trailing_comma = false}; - const Pattern* pattern = PatternFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(pattern->LineNumber(), 2); + const Pattern* pattern = PatternFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(2)); ASSERT_TRUE(isa(pattern)); } TEST(PatternTest, UnaryNoCommaAsTuplePattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->RawNew(/*line_num=*/2)}}, + .term = + global_arena->RawNew(FakeSourceLoc(2))}}, .has_trailing_comma = false}; const TuplePattern* tuple = - TuplePatternFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(tuple->LineNumber(), 1); + TuplePatternFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0"))); } TEST(PatternTest, UnaryWithCommaAsPattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->RawNew(/*line_num=*/2)}}, + .term = + global_arena->RawNew(FakeSourceLoc(2))}}, .has_trailing_comma = true}; - const Pattern* pattern = PatternFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(pattern->LineNumber(), 1); + const Pattern* pattern = PatternFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(1)); ASSERT_TRUE(isa(pattern)); EXPECT_THAT(cast(pattern)->Fields(), ElementsAre(AutoFieldNamed("0"))); @@ -88,25 +95,28 @@ TEST(PatternTest, UnaryWithCommaAsPattern) { TEST(PatternTest, UnaryWithCommaAsTuplePattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->RawNew(/*line_num=*/2)}}, + .term = + global_arena->RawNew(FakeSourceLoc(2))}}, .has_trailing_comma = true}; const TuplePattern* tuple = - TuplePatternFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(tuple->LineNumber(), 1); + TuplePatternFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0"))); } TEST(PatternTest, BinaryAsPattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->RawNew(/*line_num=*/2)}, + .term = + global_arena->RawNew(FakeSourceLoc(2))}, {.name = std::nullopt, - .term = global_arena->RawNew(/*line_num=*/3)}}, + .term = + global_arena->RawNew(FakeSourceLoc(2))}}, .has_trailing_comma = true}; - const Pattern* pattern = PatternFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(pattern->LineNumber(), 1); + const Pattern* pattern = PatternFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(1)); ASSERT_TRUE(isa(pattern)); EXPECT_THAT(cast(pattern)->Fields(), ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1"))); @@ -115,14 +125,16 @@ TEST(PatternTest, BinaryAsPattern) { TEST(PatternTest, BinaryAsTuplePattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->RawNew(/*line_num=*/2)}, + .term = + global_arena->RawNew(FakeSourceLoc(2))}, {.name = std::nullopt, - .term = global_arena->RawNew(/*line_num=*/3)}}, + .term = + global_arena->RawNew(FakeSourceLoc(2))}}, .has_trailing_comma = true}; const TuplePattern* tuple = - TuplePatternFromParenContents(/*line_num=*/1, contents); - EXPECT_EQ(tuple->LineNumber(), 1); + TuplePatternFromParenContents(FakeSourceLoc(1), contents); + EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1"))); } diff --git a/executable_semantics/ast/source_location.h b/executable_semantics/ast/source_location.h new file mode 100644 index 000000000000..55acadf1cbac --- /dev/null +++ b/executable_semantics/ast/source_location.h @@ -0,0 +1,45 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef EXECUTABLE_SEMANTICS_AST_SOURCE_LOCATION_H_ +#define EXECUTABLE_SEMANTICS_AST_SOURCE_LOCATION_H_ + +#include +#include + +#include "common/ostream.h" +#include "executable_semantics/common/ptr.h" + +namespace Carbon { + +class SourceLocation { + public: + // The filename should be eternal or arena-allocated to eliminate copies. + SourceLocation(const char* filename, int line_num) + : filename(filename), line_num(line_num) {} + SourceLocation(Ptr filename, int line_num) + : filename(filename->c_str()), line_num(line_num) {} + + SourceLocation(const SourceLocation&) = default; + SourceLocation(SourceLocation&&) = default; + auto operator=(const SourceLocation&) -> SourceLocation& = default; + auto operator=(SourceLocation&&) -> SourceLocation& = default; + + bool operator==(SourceLocation other) const { + return filename == other.filename && line_num == other.line_num; + } + + void Print(llvm::raw_ostream& out) const { + out << filename << ":" << line_num; + } + LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); } + + private: + std::string_view filename; + int line_num; +}; + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_AST_SOURCE_LOCATION_H_ diff --git a/executable_semantics/ast/statement.cpp b/executable_semantics/ast/statement.cpp index 7c2639176ebb..cdf6e5d32dc4 100644 --- a/executable_semantics/ast/statement.cpp +++ b/executable_semantics/ast/statement.cpp @@ -130,9 +130,9 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const { } } -Return::Return(int line_num, const Expression* exp, bool is_omitted_exp) - : Statement(Kind::Return, line_num), - exp(exp != nullptr ? exp : global_arena->RawNew(line_num)), +Return::Return(SourceLocation loc, const Expression* exp, bool is_omitted_exp) + : Statement(Kind::Return, loc), + exp(exp != nullptr ? exp : global_arena->RawNew(loc)), is_omitted_exp(is_omitted_exp) { CHECK(exp != nullptr || is_omitted_exp); } diff --git a/executable_semantics/ast/statement.h b/executable_semantics/ast/statement.h index c776b63ffc42..0ee79101a9db 100644 --- a/executable_semantics/ast/statement.h +++ b/executable_semantics/ast/statement.h @@ -10,6 +10,7 @@ #include "common/ostream.h" #include "executable_semantics/ast/expression.h" #include "executable_semantics/ast/pattern.h" +#include "executable_semantics/ast/source_location.h" #include "llvm/Support/Compiler.h" namespace Carbon { @@ -37,7 +38,7 @@ class Statement { // object. auto Tag() const -> Kind { return tag; } - auto LineNumber() const -> int { return line_num; } + auto SourceLoc() const -> SourceLocation { return loc; } void Print(llvm::raw_ostream& out) const { PrintDepth(-1, out); } void PrintDepth(int depth, llvm::raw_ostream& out) const; @@ -47,17 +48,17 @@ class Statement { // Constructs an Statement representing syntax at the given line number. // `tag` must be the enumerator corresponding to the most-derived type being // constructed. - Statement(Kind tag, int line_num) : tag(tag), line_num(line_num) {} + Statement(Kind tag, SourceLocation loc) : tag(tag), loc(loc) {} private: const Kind tag; - int line_num; + SourceLocation loc; }; class ExpressionStatement : public Statement { public: - ExpressionStatement(int line_num, const Expression* exp) - : Statement(Kind::ExpressionStatement, line_num), exp(exp) {} + ExpressionStatement(SourceLocation loc, const Expression* exp) + : Statement(Kind::ExpressionStatement, loc), exp(exp) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::ExpressionStatement; @@ -71,8 +72,8 @@ class ExpressionStatement : public Statement { class Assign : public Statement { public: - Assign(int line_num, const Expression* lhs, const Expression* rhs) - : Statement(Kind::Assign, line_num), lhs(lhs), rhs(rhs) {} + Assign(SourceLocation loc, const Expression* lhs, const Expression* rhs) + : Statement(Kind::Assign, loc), lhs(lhs), rhs(rhs) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Assign; @@ -88,8 +89,9 @@ class Assign : public Statement { class VariableDefinition : public Statement { public: - VariableDefinition(int line_num, const Pattern* pat, const Expression* init) - : Statement(Kind::VariableDefinition, line_num), pat(pat), init(init) {} + VariableDefinition(SourceLocation loc, const Pattern* pat, + const Expression* init) + : Statement(Kind::VariableDefinition, loc), pat(pat), init(init) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::VariableDefinition; @@ -105,9 +107,9 @@ class VariableDefinition : public Statement { class If : public Statement { public: - If(int line_num, const Expression* cond, const Statement* then_stmt, + If(SourceLocation loc, const Expression* cond, const Statement* then_stmt, const Statement* else_stmt) - : Statement(Kind::If, line_num), + : Statement(Kind::If, loc), cond(cond), then_stmt(then_stmt), else_stmt(else_stmt) {} @@ -128,7 +130,7 @@ class If : public Statement { class Return : public Statement { public: - Return(int line_num, const Expression* exp, bool is_omitted_exp); + Return(SourceLocation loc, const Expression* exp, bool is_omitted_exp); static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Return; @@ -144,8 +146,8 @@ class Return : public Statement { class Sequence : public Statement { public: - Sequence(int line_num, const Statement* stmt, const Statement* next) - : Statement(Kind::Sequence, line_num), stmt(stmt), next(next) {} + Sequence(SourceLocation loc, const Statement* stmt, const Statement* next) + : Statement(Kind::Sequence, loc), stmt(stmt), next(next) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Sequence; @@ -161,8 +163,8 @@ class Sequence : public Statement { class Block : public Statement { public: - Block(int line_num, const Statement* stmt) - : Statement(Kind::Block, line_num), stmt(stmt) {} + Block(SourceLocation loc, const Statement* stmt) + : Statement(Kind::Block, loc), stmt(stmt) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Block; @@ -176,8 +178,8 @@ class Block : public Statement { class While : public Statement { public: - While(int line_num, const Expression* cond, const Statement* body) - : Statement(Kind::While, line_num), cond(cond), body(body) {} + While(SourceLocation loc, const Expression* cond, const Statement* body) + : Statement(Kind::While, loc), cond(cond), body(body) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::While; @@ -193,7 +195,7 @@ class While : public Statement { class Break : public Statement { public: - explicit Break(int line_num) : Statement(Kind::Break, line_num) {} + explicit Break(SourceLocation loc) : Statement(Kind::Break, loc) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Break; @@ -202,7 +204,7 @@ class Break : public Statement { class Continue : public Statement { public: - explicit Continue(int line_num) : Statement(Kind::Continue, line_num) {} + explicit Continue(SourceLocation loc) : Statement(Kind::Continue, loc) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Continue; @@ -211,9 +213,9 @@ class Continue : public Statement { class Match : public Statement { public: - Match(int line_num, const Expression* exp, + Match(SourceLocation loc, const Expression* exp, std::list>* clauses) - : Statement(Kind::Match, line_num), exp(exp), clauses(clauses) {} + : Statement(Kind::Match, loc), exp(exp), clauses(clauses) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Match; @@ -237,9 +239,9 @@ class Match : public Statement { // } class Continuation : public Statement { public: - Continuation(int line_num, std::string continuation_variable, + Continuation(SourceLocation loc, std::string continuation_variable, const Statement* body) - : Statement(Kind::Continuation, line_num), + : Statement(Kind::Continuation, loc), continuation_variable(std::move(continuation_variable)), body(body) {} @@ -262,8 +264,8 @@ class Continuation : public Statement { // __run ; class Run : public Statement { public: - Run(int line_num, const Expression* argument) - : Statement(Kind::Run, line_num), argument(argument) {} + Run(SourceLocation loc, const Expression* argument) + : Statement(Kind::Run, loc), argument(argument) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Run; @@ -280,7 +282,7 @@ class Run : public Statement { // __await; class Await : public Statement { public: - explicit Await(int line_num) : Statement(Kind::Await, line_num) {} + explicit Await(SourceLocation loc) : Statement(Kind::Await, loc) {} static auto classof(const Statement* stmt) -> bool { return stmt->Tag() == Kind::Await; diff --git a/executable_semantics/interpreter/heap.cpp b/executable_semantics/interpreter/heap.cpp index 0dff7e4b26e0..7ad5e6f43497 100644 --- a/executable_semantics/interpreter/heap.cpp +++ b/executable_semantics/interpreter/heap.cpp @@ -21,21 +21,21 @@ auto Heap::AllocateValue(const Value* v) -> Address { return a; } -auto Heap::Read(const Address& a, int line_num) -> const Value* { - this->CheckAlive(a, line_num); - return values_[a.index]->GetField(a.field_path, line_num); +auto Heap::Read(const Address& a, SourceLocation loc) -> const Value* { + this->CheckAlive(a, loc); + return values_[a.index]->GetField(a.field_path, loc); } -void Heap::Write(const Address& a, const Value* v, int line_num) { +void Heap::Write(const Address& a, const Value* v, SourceLocation loc) { CHECK(v != nullptr); - this->CheckAlive(a, line_num); - values_[a.index] = values_[a.index]->SetField(a.field_path, v, line_num); + this->CheckAlive(a, loc); + values_[a.index] = values_[a.index]->SetField(a.field_path, v, loc); } -void Heap::CheckAlive(const Address& address, int line_num) { +void Heap::CheckAlive(const Address& address, SourceLocation loc) { if (!alive_[address.index]) { - FATAL_RUNTIME_ERROR(line_num) << "undefined behavior: access to dead value " - << *values_[address.index]; + FATAL_RUNTIME_ERROR(loc) << "undefined behavior: access to dead value " + << *values_[address.index]; } } diff --git a/executable_semantics/interpreter/heap.h b/executable_semantics/interpreter/heap.h index 27d42c91cb14..9ff2d9b915ff 100644 --- a/executable_semantics/interpreter/heap.h +++ b/executable_semantics/interpreter/heap.h @@ -25,11 +25,11 @@ class Heap { // Returns the value at the given address in the heap after // checking that it is alive. - auto Read(const Address& a, int line_num) -> const Value*; + auto Read(const Address& a, SourceLocation loc) -> const Value*; // Writes the given value at the address in the heap after // checking that the address is alive. - void Write(const Address& a, const Value* v, int line_num); + void Write(const Address& a, const Value* v, SourceLocation loc); // Put the given value on the heap and mark it as alive. auto AllocateValue(const Value* v) -> Address; @@ -47,7 +47,7 @@ class Heap { private: // Signal an error if the address is no longer alive. - void CheckAlive(const Address& address, int line_num); + void CheckAlive(const Address& address, SourceLocation loc); std::vector values_; std::vector alive_; diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 93bac533c287..20024d17edc2 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -62,10 +62,10 @@ auto CurrentEnv(State* state) -> Env { } // Returns the given name from the environment, printing an error if not found. -static auto GetFromEnv(int line_num, const std::string& name) -> Address { +static auto GetFromEnv(SourceLocation loc, const std::string& name) -> Address { std::optional
pointer = CurrentEnv(state).Get(name); if (!pointer) { - FATAL_RUNTIME_ERROR(line_num) << "could not find `" << name << "`"; + FATAL_RUNTIME_ERROR(loc) << "could not find `" << name << "`"; } return *pointer; } @@ -81,8 +81,8 @@ void PrintState(llvm::raw_ostream& out) { out << "\n}\n"; } -auto EvalPrim(Operator op, const std::vector& args, int line_num) - -> const Value* { +auto EvalPrim(Operator op, const std::vector& args, + SourceLocation loc) -> const Value* { switch (op) { case Operator::Neg: return global_arena->RawNew(-cast(*args[0]).Val()); @@ -104,8 +104,7 @@ auto EvalPrim(Operator op, const std::vector& args, int line_num) return global_arena->RawNew(cast(*args[0]).Val() || cast(*args[1]).Val()); case Operator::Eq: - return global_arena->RawNew( - ValueEqual(args[0], args[1], line_num)); + return global_arena->RawNew(ValueEqual(args[0], args[1], loc)); case Operator::Ptr: return global_arena->RawNew(args[0]); case Operator::Deref: @@ -220,14 +219,14 @@ const Value* CreateTuple(Ptr act, const Expression* exp) { return global_arena->RawNew(std::move(elements)); } -auto PatternMatch(const Value* p, const Value* v, int line_num) +auto PatternMatch(const Value* p, const Value* v, SourceLocation loc) -> std::optional { switch (p->Tag()) { case Value::Kind::BindingPlaceholderValue: { const auto& placeholder = cast(*p); Env values; if (placeholder.Name().has_value()) { - Address a = state->heap.AllocateValue(CopyVal(v, line_num)); + Address a = state->heap.AllocateValue(CopyVal(v, loc)); values.Set(*placeholder.Name(), a); } return values; @@ -238,20 +237,20 @@ auto PatternMatch(const Value* p, const Value* v, int line_num) const auto& p_tup = cast(*p); const auto& v_tup = cast(*v); if (p_tup.Elements().size() != v_tup.Elements().size()) { - FATAL_PROGRAM_ERROR(line_num) + FATAL_PROGRAM_ERROR(loc) << "arity mismatch in tuple pattern match:\n pattern: " << p_tup << "\n value: " << v_tup; } Env values; for (size_t i = 0; i < p_tup.Elements().size(); ++i) { if (p_tup.Elements()[i].name != v_tup.Elements()[i].name) { - FATAL_PROGRAM_ERROR(line_num) + FATAL_PROGRAM_ERROR(loc) << "Tuple field name '" << v_tup.Elements()[i].name << "' does not match pattern field name '" << p_tup.Elements()[i].name << "'"; } std::optional matches = PatternMatch( - p_tup.Elements()[i].value, v_tup.Elements()[i].value, line_num); + p_tup.Elements()[i].value, v_tup.Elements()[i].value, loc); if (!matches) { return std::nullopt; } @@ -273,7 +272,7 @@ auto PatternMatch(const Value* p, const Value* v, int line_num) p_alt.AltName() != v_alt.AltName()) { return std::nullopt; } - return PatternMatch(p_alt.Argument(), v_alt.Argument(), line_num); + return PatternMatch(p_alt.Argument(), v_alt.Argument(), loc); } default: FATAL() << "expected a choice alternative in pattern, not " << *v; @@ -284,12 +283,12 @@ auto PatternMatch(const Value* p, const Value* v, int line_num) const auto& p_fn = cast(*p); const auto& v_fn = cast(*v); std::optional param_matches = - PatternMatch(p_fn.Param(), v_fn.Param(), line_num); + PatternMatch(p_fn.Param(), v_fn.Param(), loc); if (!param_matches) { return std::nullopt; } std::optional ret_matches = - PatternMatch(p_fn.Ret(), v_fn.Ret(), line_num); + PatternMatch(p_fn.Ret(), v_fn.Ret(), loc); if (!ret_matches) { return std::nullopt; } @@ -307,7 +306,7 @@ auto PatternMatch(const Value* p, const Value* v, int line_num) // on the typechecker to ensure that `v` is a type. return Env(); default: - if (ValueEqual(p, v, line_num)) { + if (ValueEqual(p, v, loc)) { return Env(); } else { return std::nullopt; @@ -315,11 +314,10 @@ auto PatternMatch(const Value* p, const Value* v, int line_num) } } -void PatternAssignment(const Value* pat, const Value* val, int line_num) { +void PatternAssignment(const Value* pat, const Value* val, SourceLocation loc) { switch (pat->Tag()) { case Value::Kind::PointerValue: - state->heap.Write(cast(*pat).Val(), CopyVal(val, line_num), - line_num); + state->heap.Write(cast(*pat).Val(), CopyVal(val, loc), loc); break; case Value::Kind::TupleValue: { switch (val->Tag()) { @@ -327,17 +325,17 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) { const auto& pat_tup = cast(*pat); const auto& val_tup = cast(*val); if (pat_tup.Elements().size() != val_tup.Elements().size()) { - FATAL_RUNTIME_ERROR(line_num) + FATAL_RUNTIME_ERROR(loc) << "arity mismatch in tuple pattern assignment:\n pattern: " << pat_tup << "\n value: " << val_tup; } for (const TupleElement& pattern_element : pat_tup.Elements()) { const Value* value_field = val_tup.FindField(pattern_element.name); if (value_field == nullptr) { - FATAL_RUNTIME_ERROR(line_num) + FATAL_RUNTIME_ERROR(loc) << "field " << pattern_element.name << "not in " << *val; } - PatternAssignment(pattern_element.value, value_field, line_num); + PatternAssignment(pattern_element.value, value_field, loc); } break; } @@ -354,7 +352,7 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) { CHECK(val_alt.ChoiceName() == pat_alt.ChoiceName() && val_alt.AltName() == pat_alt.AltName()) << "internal error in pattern assignment"; - PatternAssignment(pat_alt.Argument(), val_alt.Argument(), line_num); + PatternAssignment(pat_alt.Argument(), val_alt.Argument(), loc); break; } default: @@ -363,7 +361,7 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) { break; } default: - CHECK(ValueEqual(pat, val, line_num)) + CHECK(ValueEqual(pat, val, loc)) << "internal error in pattern assignment"; } } @@ -417,7 +415,7 @@ struct UnwindFunctionCall { struct CallFunction { const FunctionValue* function; const Value* args; - int line_num; + SourceLocation loc; }; // Transition type which does nothing. @@ -441,8 +439,8 @@ Transition StepLvalue() { case Expression::Kind::IdentifierExpression: { // { {x :: C, E, F} :: S, H} // -> { {E(x) :: C, E, F} :: S, H} - Address pointer = GetFromEnv(exp->LineNumber(), - cast(*exp).Name()); + Address pointer = + GetFromEnv(exp->SourceLoc(), cast(*exp).Name()); const Value* v = global_arena->RawNew(pointer); return Done{v}; } @@ -586,15 +584,15 @@ Transition StepExp() { // { { v :: [].f :: C, E, F} :: S, H} // -> { { v_f :: C, E, F} : S, H} return Done{act->Results()[0]->GetField(FieldPath(access.Field()), - exp->LineNumber())}; + exp->SourceLoc())}; } } case Expression::Kind::IdentifierExpression: { CHECK(act->Pos() == 0); const auto& ident = cast(*exp); // { {x :: C, E, F} :: S, H} -> { {H(E(x)) :: C, E, F} :: S, H} - Address pointer = GetFromEnv(exp->LineNumber(), ident.Name()); - return Done{state->heap.Read(pointer, exp->LineNumber())}; + Address pointer = GetFromEnv(exp->SourceLoc(), ident.Name()); + return Done{state->heap.Read(pointer, exp->SourceLoc())}; } case Expression::Kind::IntLiteral: CHECK(act->Pos() == 0); @@ -615,7 +613,7 @@ Transition StepExp() { } else { // { {v :: op(vs,[]) :: C, E, F} :: S, H} // -> { {eval_prim(op, (vs,v)) :: C, E, F} :: S, H} - return Done{EvalPrim(op.Op(), act->Results(), exp->LineNumber())}; + return Done{EvalPrim(op.Op(), act->Results(), exp->SourceLoc())}; } } case Expression::Kind::CallExpression: @@ -634,14 +632,14 @@ Transition StepExp() { // -> { {C',E',F'} :: {C, E, F} :: S, H} switch (act->Results()[0]->Tag()) { case Value::Kind::ClassType: { - const Value* arg = CopyVal(act->Results()[1], exp->LineNumber()); + const Value* arg = CopyVal(act->Results()[1], exp->SourceLoc()); return Done{ global_arena->RawNew(act->Results()[0], arg)}; } case Value::Kind::AlternativeConstructorValue: { const auto& alt = cast(*act->Results()[0]); - const Value* arg = CopyVal(act->Results()[1], exp->LineNumber()); + const Value* arg = CopyVal(act->Results()[1], exp->SourceLoc()); return Done{global_arena->RawNew( alt.AltName(), alt.ChoiceName(), arg)}; } @@ -649,9 +647,9 @@ Transition StepExp() { return CallFunction{ .function = cast(act->Results()[0]), .args = act->Results()[1], - .line_num = exp->LineNumber()}; + .loc = exp->SourceLoc()}; default: - FATAL_RUNTIME_ERROR(exp->LineNumber()) + FATAL_RUNTIME_ERROR(exp->SourceLoc()) << "in call, expected a function, not " << *act->Results()[0]; } } else { @@ -662,8 +660,8 @@ Transition StepExp() { // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} switch (cast(*exp).Intrinsic()) { case IntrinsicExpression::IntrinsicKind::Print: - Address pointer = GetFromEnv(exp->LineNumber(), "format_str"); - const Value* pointee = state->heap.Read(pointer, exp->LineNumber()); + Address pointer = GetFromEnv(exp->SourceLoc(), "format_str"); + const Value* pointee = state->heap.Read(pointer, exp->SourceLoc()); CHECK(pointee->Tag() == Value::Kind::StringValue); // TODO: This could eventually use something like llvm::formatv. llvm::outs() << cast(*pointee).Val(); @@ -853,7 +851,7 @@ Transition StepStmt() { } else { // try to match auto v = act->Results()[0]; auto pat = act->Results()[clause_num + 1]; - std::optional matches = PatternMatch(pat, v, stmt->LineNumber()); + std::optional matches = PatternMatch(pat, v, stmt->SourceLoc()); if (matches) { // we have a match, start the body Env values = CurrentEnv(state); std::list vars; @@ -863,7 +861,7 @@ Transition StepStmt() { } frame->scopes.Push(global_arena->New(values, vars)); const Statement* body_block = - global_arena->RawNew(stmt->LineNumber(), c->second); + global_arena->RawNew(stmt->SourceLoc(), c->second); auto body_act = global_arena->New(body_block); body_act->IncrementPos(); frame->todo.Pop(1); @@ -905,7 +903,7 @@ Transition StepStmt() { auto it = std::find_if(frame->todo.begin(), frame->todo.end(), &IsWhileAct); if (it == frame->todo.end()) { - FATAL_RUNTIME_ERROR(stmt->LineNumber()) + FATAL_RUNTIME_ERROR(stmt->SourceLoc()) << "`break` not inside `while` statement"; } ++it; @@ -918,7 +916,7 @@ Transition StepStmt() { auto it = std::find_if(frame->todo.begin(), frame->todo.end(), &IsWhileAct); if (it == frame->todo.end()) { - FATAL_RUNTIME_ERROR(stmt->LineNumber()) + FATAL_RUNTIME_ERROR(stmt->SourceLoc()) << "`continue` not inside `while` statement"; } return UnwindTo{*it}; @@ -954,9 +952,9 @@ Transition StepStmt() { const Value* v = act->Results()[0]; const Value* p = act->Results()[1]; - std::optional matches = PatternMatch(p, v, stmt->LineNumber()); + std::optional matches = PatternMatch(p, v, stmt->SourceLoc()); CHECK(matches) - << stmt->LineNumber() + << stmt->SourceLoc() << ": internal error in variable definition, match failed"; for (const auto& [name, value] : *matches) { frame->scopes.Top()->values.Set(name, value); @@ -988,7 +986,7 @@ Transition StepStmt() { // -> { { C, E, F} :: S, H(a := v)} auto pat = act->Results()[0]; auto val = act->Results()[1]; - PatternAssignment(pat, val, stmt->LineNumber()); + PatternAssignment(pat, val, stmt->SourceLoc()); return Done{}; } case Statement::Kind::If: @@ -1021,7 +1019,7 @@ Transition StepStmt() { } else { // { {v :: return [] :: C, E, F} :: {C', E', F'} :: S, H} // -> { {v :: C', E', F'} :: S, H} - const Value* ret_val = CopyVal(act->Results()[0], stmt->LineNumber()); + const Value* ret_val = CopyVal(act->Results()[0], stmt->SourceLoc()); return UnwindFunctionCall{ret_val}; } case Statement::Kind::Sequence: { @@ -1047,7 +1045,7 @@ Transition StepStmt() { Stack>(global_arena->New(CurrentEnv(state))); Stack> todo; todo.Push(global_arena->New( - global_arena->RawNew(stmt->LineNumber(), nullptr, + global_arena->RawNew(stmt->SourceLoc(), nullptr, /*is_omitted_exp=*/true))); todo.Push( global_arena->New(cast(*stmt).Body())); @@ -1077,8 +1075,8 @@ Transition StepStmt() { // value from the continuation. auto ignore_result = global_arena->New( global_arena->RawNew( - stmt->LineNumber(), - global_arena->RawNew(stmt->LineNumber()))); + stmt->SourceLoc(), + global_arena->RawNew(stmt->SourceLoc()))); frame->todo.Push(ignore_result); // Push the continuation onto the current stack. const std::vector>& continuation_vector = @@ -1100,7 +1098,7 @@ Transition StepStmt() { // Update the continuation with the paused stack. state->heap.Write(*paused.back()->continuation, global_arena->RawNew(paused), - stmt->LineNumber()); + stmt->SourceLoc()); return ManualTransition{}; } } @@ -1164,7 +1162,7 @@ struct DoTransition { void operator()(const CallFunction& call) { state->stack.Top()->todo.Pop(); std::optional matches = - PatternMatch(call.function->Param(), call.args, call.line_num); + PatternMatch(call.function->Param(), call.args, call.loc); CHECK(matches.has_value()) << "internal error in call_function, pattern match failed"; // Create the new frame and push it on the stack @@ -1217,9 +1215,11 @@ auto InterpProgram(const std::list>& fs) -> int { } InitGlobals(fs); - const Expression* arg = global_arena->RawNew(0); + SourceLocation loc("", 0); + + const Expression* arg = global_arena->RawNew(loc); const Expression* call_main = global_arena->RawNew( - 0, global_arena->RawNew(0, "main"), arg); + loc, global_arena->RawNew(loc, "main"), arg); auto todo = Stack>(global_arena->New(call_main)); auto scopes = Stack>(global_arena->New(globals)); diff --git a/executable_semantics/interpreter/interpreter.h b/executable_semantics/interpreter/interpreter.h index d726f7435da6..c1a2872b7e98 100644 --- a/executable_semantics/interpreter/interpreter.h +++ b/executable_semantics/interpreter/interpreter.h @@ -39,7 +39,7 @@ void PrintEnv(Env values, llvm::raw_ostream& out); // Attempts to match `v` against the pattern `p`. If matching succeeds, returns // the bindings of pattern variables to their matched values. -auto PatternMatch(const Value* p, const Value* v, int line_num) +auto PatternMatch(const Value* p, const Value* v, SourceLocation loc) -> std::optional; auto InterpProgram(const std::list>& fs) -> int; diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index 9a99a024e882..0bbd96d53469 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -32,66 +32,71 @@ void PrintTypeEnv(TypeEnv types, llvm::raw_ostream& out) { } } -static void ExpectType(int line_num, const std::string& context, +static void ExpectType(SourceLocation loc, const std::string& context, const Value* expected, const Value* actual) { if (!TypeEqual(expected, actual)) { - FATAL_COMPILATION_ERROR(line_num) << "type error in " << context << "\n" - << "expected: " << *expected << "\n" - << "actual: " << *actual; + FATAL_COMPILATION_ERROR(loc) << "type error in " << context << "\n" + << "expected: " << *expected << "\n" + << "actual: " << *actual; } } -static void ExpectPointerType(int line_num, const std::string& context, +static void ExpectPointerType(SourceLocation loc, const std::string& context, const Value* actual) { if (actual->Tag() != Value::Kind::PointerType) { - FATAL_COMPILATION_ERROR(line_num) << "type error in " << context << "\n" - << "expected a pointer type\n" - << "actual: " << *actual; + FATAL_COMPILATION_ERROR(loc) << "type error in " << context << "\n" + << "expected a pointer type\n" + << "actual: " << *actual; } } +static SourceLocation ReifyFakeSourceLoc() { + return SourceLocation("", 0); +} + // Reify type to type expression. -static auto ReifyType(const Value* t, int line_num) -> const Expression* { +static auto ReifyType(const Value* t, SourceLocation loc) -> const Expression* { switch (t->Tag()) { case Value::Kind::IntType: - return global_arena->RawNew(0); + return global_arena->RawNew(ReifyFakeSourceLoc()); case Value::Kind::BoolType: - return global_arena->RawNew(0); + return global_arena->RawNew(ReifyFakeSourceLoc()); case Value::Kind::TypeType: - return global_arena->RawNew(0); + return global_arena->RawNew(ReifyFakeSourceLoc()); case Value::Kind::ContinuationType: - return global_arena->RawNew(0); + return global_arena->RawNew( + ReifyFakeSourceLoc()); case Value::Kind::FunctionType: { const auto& fn_type = cast(*t); return global_arena->RawNew( - 0, ReifyType(fn_type.Param(), line_num), - ReifyType(fn_type.Ret(), line_num), + ReifyFakeSourceLoc(), ReifyType(fn_type.Param(), loc), + ReifyType(fn_type.Ret(), loc), /*is_omitted_return_type=*/false); } case Value::Kind::TupleValue: { std::vector args; for (const TupleElement& field : cast(*t).Elements()) { args.push_back( - FieldInitializer(field.name, ReifyType(field.value, line_num))); + FieldInitializer(field.name, ReifyType(field.value, loc))); } - return global_arena->RawNew(0, args); + return global_arena->RawNew(ReifyFakeSourceLoc(), args); } case Value::Kind::ClassType: return global_arena->RawNew( - 0, cast(*t).Name()); + ReifyFakeSourceLoc(), cast(*t).Name()); case Value::Kind::ChoiceType: return global_arena->RawNew( - 0, cast(*t).Name()); + ReifyFakeSourceLoc(), cast(*t).Name()); case Value::Kind::PointerType: return global_arena->RawNew( - 0, Operator::Ptr, + ReifyFakeSourceLoc(), Operator::Ptr, std::vector( - {ReifyType(cast(*t).Type(), line_num)})); + {ReifyType(cast(*t).Type(), loc)})); case Value::Kind::VariableType: return global_arena->RawNew( - 0, cast(*t).Name()); + ReifyFakeSourceLoc(), cast(*t).Name()); case Value::Kind::StringType: - return global_arena->RawNew(0); + return global_arena->RawNew(ReifyFakeSourceLoc()); case Value::Kind::AlternativeConstructorValue: case Value::Kind::AlternativeValue: case Value::Kind::AutoType: @@ -113,8 +118,8 @@ static auto ReifyType(const Value* t, int line_num) -> const Expression* { // inside the argument type. // The `deduced` parameter is an accumulator, that is, it holds the // results so-far. -static auto ArgumentDeduction(int line_num, TypeEnv deduced, const Value* param, - const Value* arg) -> TypeEnv { +static auto ArgumentDeduction(SourceLocation loc, TypeEnv deduced, + const Value* param, const Value* arg) -> TypeEnv { switch (param->Tag()) { case Value::Kind::VariableType: { const auto& var_type = cast(*param); @@ -122,50 +127,47 @@ static auto ArgumentDeduction(int line_num, TypeEnv deduced, const Value* param, if (!d) { deduced.Set(var_type.Name(), arg); } else { - ExpectType(line_num, "argument deduction", *d, arg); + ExpectType(loc, "argument deduction", *d, arg); } return deduced; } case Value::Kind::TupleValue: { if (arg->Tag() != Value::Kind::TupleValue) { - ExpectType(line_num, "argument deduction", param, arg); + ExpectType(loc, "argument deduction", param, arg); } const auto& param_tup = cast(*param); const auto& arg_tup = cast(*arg); if (param_tup.Elements().size() != arg_tup.Elements().size()) { - ExpectType(line_num, "argument deduction", param, arg); + ExpectType(loc, "argument deduction", param, arg); } for (size_t i = 0; i < param_tup.Elements().size(); ++i) { if (param_tup.Elements()[i].name != arg_tup.Elements()[i].name) { - FATAL_COMPILATION_ERROR(line_num) + FATAL_COMPILATION_ERROR(loc) << "mismatch in tuple names, " << param_tup.Elements()[i].name << " != " << arg_tup.Elements()[i].name; } - deduced = - ArgumentDeduction(line_num, deduced, param_tup.Elements()[i].value, - arg_tup.Elements()[i].value); + deduced = ArgumentDeduction(loc, deduced, param_tup.Elements()[i].value, + arg_tup.Elements()[i].value); } return deduced; } case Value::Kind::FunctionType: { if (arg->Tag() != Value::Kind::FunctionType) { - ExpectType(line_num, "argument deduction", param, arg); + ExpectType(loc, "argument deduction", param, arg); } const auto& param_fn = cast(*param); const auto& arg_fn = cast(*arg); // TODO: handle situation when arg has deduced parameters. - deduced = ArgumentDeduction(line_num, deduced, param_fn.Param(), - arg_fn.Param()); deduced = - ArgumentDeduction(line_num, deduced, param_fn.Ret(), arg_fn.Ret()); + ArgumentDeduction(loc, deduced, param_fn.Param(), arg_fn.Param()); + deduced = ArgumentDeduction(loc, deduced, param_fn.Ret(), arg_fn.Ret()); return deduced; } case Value::Kind::PointerType: { if (arg->Tag() != Value::Kind::PointerType) { - ExpectType(line_num, "argument deduction", param, arg); + ExpectType(loc, "argument deduction", param, arg); } - return ArgumentDeduction(line_num, deduced, - cast(*param).Type(), + return ArgumentDeduction(loc, deduced, cast(*param).Type(), cast(*arg).Type()); } // Nothing to do in the case for `auto`. @@ -180,7 +182,7 @@ static auto ArgumentDeduction(int line_num, TypeEnv deduced, const Value* param, case Value::Kind::BoolType: case Value::Kind::TypeType: case Value::Kind::StringType: - ExpectType(line_num, "argument deduction", param, arg); + ExpectType(loc, "argument deduction", param, arg); return deduced; // The rest of these cases should never happen. case Value::Kind::IntValue: @@ -284,16 +286,16 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) std::string f = std::to_string(i); const Value* field_t = cast(*t).FindField(f); if (field_t == nullptr) { - FATAL_COMPILATION_ERROR(e->LineNumber()) + FATAL_COMPILATION_ERROR(e->SourceLoc()) << "field " << f << " is not in the tuple " << *t; } auto new_e = global_arena->RawNew( - e->LineNumber(), res.exp, - global_arena->RawNew(e->LineNumber(), i)); + e->SourceLoc(), res.exp, + global_arena->RawNew(e->SourceLoc(), i)); return TCExpression(new_e, field_t, res.types); } default: - FATAL_COMPILATION_ERROR(e->LineNumber()) << "expected a tuple"; + FATAL_COMPILATION_ERROR(e->SourceLoc()) << "expected a tuple"; } } case Expression::Kind::TupleLiteral: { @@ -307,7 +309,7 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) arg_types.push_back({.name = arg.name, .value = arg_res.type}); } auto tuple_e = - global_arena->RawNew(e->LineNumber(), new_args); + global_arena->RawNew(e->SourceLoc(), new_args); auto tuple_t = global_arena->RawNew(std::move(arg_types)); return TCExpression(tuple_e, tuple_t, new_types); } @@ -323,7 +325,7 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) if (access.Field() == field.first) { const Expression* new_e = global_arena->RawNew( - e->LineNumber(), res.exp, access.Field()); + e->SourceLoc(), res.exp, access.Field()); return TCExpression(new_e, field.second, res.types); } } @@ -332,11 +334,11 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) if (access.Field() == method.first) { const Expression* new_e = global_arena->RawNew( - e->LineNumber(), res.exp, access.Field()); + e->SourceLoc(), res.exp, access.Field()); return TCExpression(new_e, method.second, res.types); } } - FATAL_COMPILATION_ERROR(e->LineNumber()) + FATAL_COMPILATION_ERROR(e->SourceLoc()) << "class " << t_class.Name() << " does not have a field named " << access.Field(); } @@ -345,11 +347,11 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) for (const TupleElement& field : tup.Elements()) { if (access.Field() == field.name) { auto new_e = global_arena->RawNew( - e->LineNumber(), res.exp, access.Field()); + e->SourceLoc(), res.exp, access.Field()); return TCExpression(new_e, field.value, res.types); } } - FATAL_COMPILATION_ERROR(e->LineNumber()) + FATAL_COMPILATION_ERROR(e->SourceLoc()) << "tuple " << tup << " does not have a field named " << access.Field(); } @@ -359,18 +361,18 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) if (access.Field() == vt.first) { const Expression* new_e = global_arena->RawNew( - e->LineNumber(), res.exp, access.Field()); + e->SourceLoc(), res.exp, access.Field()); auto fun_ty = global_arena->RawNew( std::vector(), vt.second, t); return TCExpression(new_e, fun_ty, res.types); } } - FATAL_COMPILATION_ERROR(e->LineNumber()) + FATAL_COMPILATION_ERROR(e->SourceLoc()) << "choice " << choice.Name() << " does not have a field named " << access.Field(); } default: - FATAL_COMPILATION_ERROR(e->LineNumber()) + FATAL_COMPILATION_ERROR(e->SourceLoc()) << "field access, expected a struct\n" << *e; } @@ -381,7 +383,7 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) if (type) { return TCExpression(e, *type, types); } else { - FATAL_COMPILATION_ERROR(e->LineNumber()) + FATAL_COMPILATION_ERROR(e->SourceLoc()) << "could not find `" << ident.Name() << "`"; } } @@ -401,63 +403,63 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) ts.push_back(res.type); } auto new_e = global_arena->RawNew( - e->LineNumber(), op.Op(), es); + e->SourceLoc(), op.Op(), es); switch (op.Op()) { case Operator::Neg: - ExpectType(e->LineNumber(), "negation", + ExpectType(e->SourceLoc(), "negation", global_arena->RawNew(), ts[0]); return TCExpression(new_e, global_arena->RawNew(), new_types); case Operator::Add: - ExpectType(e->LineNumber(), "addition(1)", + ExpectType(e->SourceLoc(), "addition(1)", global_arena->RawNew(), ts[0]); - ExpectType(e->LineNumber(), "addition(2)", + ExpectType(e->SourceLoc(), "addition(2)", global_arena->RawNew(), ts[1]); return TCExpression(new_e, global_arena->RawNew(), new_types); case Operator::Sub: - ExpectType(e->LineNumber(), "subtraction(1)", + ExpectType(e->SourceLoc(), "subtraction(1)", global_arena->RawNew(), ts[0]); - ExpectType(e->LineNumber(), "subtraction(2)", + ExpectType(e->SourceLoc(), "subtraction(2)", global_arena->RawNew(), ts[1]); return TCExpression(new_e, global_arena->RawNew(), new_types); case Operator::Mul: - ExpectType(e->LineNumber(), "multiplication(1)", + ExpectType(e->SourceLoc(), "multiplication(1)", global_arena->RawNew(), ts[0]); - ExpectType(e->LineNumber(), "multiplication(2)", + ExpectType(e->SourceLoc(), "multiplication(2)", global_arena->RawNew(), ts[1]); return TCExpression(new_e, global_arena->RawNew(), new_types); case Operator::And: - ExpectType(e->LineNumber(), "&&(1)", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "&&(1)", global_arena->RawNew(), ts[0]); - ExpectType(e->LineNumber(), "&&(2)", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "&&(2)", global_arena->RawNew(), ts[1]); return TCExpression(new_e, global_arena->RawNew(), new_types); case Operator::Or: - ExpectType(e->LineNumber(), "||(1)", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "||(1)", global_arena->RawNew(), ts[0]); - ExpectType(e->LineNumber(), "||(2)", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "||(2)", global_arena->RawNew(), ts[1]); return TCExpression(new_e, global_arena->RawNew(), new_types); case Operator::Not: - ExpectType(e->LineNumber(), "!", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "!", global_arena->RawNew(), ts[0]); return TCExpression(new_e, global_arena->RawNew(), new_types); case Operator::Eq: - ExpectType(e->LineNumber(), "==", ts[0], ts[1]); + ExpectType(e->SourceLoc(), "==", ts[0], ts[1]); return TCExpression(new_e, global_arena->RawNew(), new_types); case Operator::Deref: - ExpectPointerType(e->LineNumber(), "*", ts[0]); + ExpectPointerType(e->SourceLoc(), "*", ts[0]); return TCExpression(new_e, cast(*ts[0]).Type(), new_types); case Operator::Ptr: - ExpectType(e->LineNumber(), "*", global_arena->RawNew(), + ExpectType(e->SourceLoc(), "*", global_arena->RawNew(), ts[0]); return TCExpression(new_e, global_arena->RawNew(), new_types); @@ -474,13 +476,13 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) auto parameter_type = fun_t.Param(); auto return_type = fun_t.Ret(); if (!fun_t.Deduced().empty()) { - auto deduced_args = ArgumentDeduction(e->LineNumber(), TypeEnv(), + auto deduced_args = ArgumentDeduction(e->SourceLoc(), TypeEnv(), parameter_type, arg_res.type); for (auto& deduced_param : fun_t.Deduced()) { // TODO: change the following to a CHECK once the real checking // has been added to the type checking of function signatures. if (!deduced_args.Get(deduced_param.name)) { - FATAL_COMPILATION_ERROR(e->LineNumber()) + FATAL_COMPILATION_ERROR(e->SourceLoc()) << "could not deduce type argument for type parameter " << deduced_param.name; } @@ -488,14 +490,14 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) parameter_type = Substitute(deduced_args, parameter_type); return_type = Substitute(deduced_args, return_type); } else { - ExpectType(e->LineNumber(), "call", parameter_type, arg_res.type); + ExpectType(e->SourceLoc(), "call", parameter_type, arg_res.type); } auto new_e = global_arena->RawNew( - e->LineNumber(), fun_res.exp, arg_res.exp); + e->SourceLoc(), fun_res.exp, arg_res.exp); return TCExpression(new_e, return_type, arg_res.types); } default: { - FATAL_COMPILATION_ERROR(e->LineNumber()) + FATAL_COMPILATION_ERROR(e->SourceLoc()) << "in call, expected a function\n" << *e; } @@ -507,8 +509,8 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) auto pt = InterpExp(values, fn.Parameter()); auto rt = InterpExp(values, fn.ReturnType()); auto new_e = global_arena->RawNew( - e->LineNumber(), ReifyType(pt, e->LineNumber()), - ReifyType(rt, e->LineNumber()), + e->SourceLoc(), ReifyType(pt, e->SourceLoc()), + ReifyType(rt, e->SourceLoc()), /*is_omitted_return_type=*/false); return TCExpression(new_e, global_arena->RawNew(), types); } @@ -557,9 +559,9 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, const Value* type = InterpPattern(values, binding_type_result.pattern); if (expected != nullptr) { std::optional values = - PatternMatch(type, expected, binding.Type()->LineNumber()); + PatternMatch(type, expected, binding.Type()->SourceLoc()); if (values == std::nullopt) { - FATAL_COMPILATION_ERROR(binding.Type()->LineNumber()) + FATAL_COMPILATION_ERROR(binding.Type()->SourceLoc()) << "Type pattern '" << *type << "' does not match actual type '" << *expected << "'"; } @@ -568,9 +570,9 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, type = expected; } auto new_p = global_arena->RawNew( - binding.LineNumber(), binding.Name(), + binding.SourceLoc(), binding.Name(), global_arena->RawNew( - ReifyType(type, binding.LineNumber()))); + ReifyType(type, binding.SourceLoc()))); if (binding.Name().has_value()) { types.Set(*binding.Name(), type); } @@ -582,11 +584,11 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, std::vector field_types; auto new_types = types; if (expected && expected->Tag() != Value::Kind::TupleValue) { - FATAL_COMPILATION_ERROR(p->LineNumber()) << "didn't expect a tuple"; + FATAL_COMPILATION_ERROR(p->SourceLoc()) << "didn't expect a tuple"; } if (expected && tuple.Fields().size() != cast(*expected).Elements().size()) { - FATAL_COMPILATION_ERROR(tuple.LineNumber()) + FATAL_COMPILATION_ERROR(tuple.SourceLoc()) << "tuples of different length"; } for (size_t i = 0; i < tuple.Fields().size(); ++i) { @@ -596,7 +598,7 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, const TupleElement& expected_element = cast(*expected).Elements()[i]; if (expected_element.name != field.name) { - FATAL_COMPILATION_ERROR(tuple.LineNumber()) + FATAL_COMPILATION_ERROR(tuple.SourceLoc()) << "field names do not match, expected " << expected_element.name << " but got " << field.name; } @@ -610,7 +612,7 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, field_types.push_back({.name = field.name, .value = field_result.type}); } auto new_tuple = - global_arena->RawNew(tuple.LineNumber(), new_fields); + global_arena->RawNew(tuple.SourceLoc(), new_fields); auto tuple_t = global_arena->RawNew(std::move(field_types)); return {.pattern = new_tuple, .type = tuple_t, .types = new_types}; } @@ -618,26 +620,26 @@ auto TypeCheckPattern(const Pattern* p, TypeEnv types, Env values, const auto& alternative = cast(*p); const Value* choice_type = InterpExp(values, alternative.ChoiceType()); if (choice_type->Tag() != Value::Kind::ChoiceType) { - FATAL_COMPILATION_ERROR(alternative.LineNumber()) + FATAL_COMPILATION_ERROR(alternative.SourceLoc()) << "alternative pattern does not name a choice type."; } if (expected != nullptr) { - ExpectType(alternative.LineNumber(), "alternative pattern", expected, + ExpectType(alternative.SourceLoc(), "alternative pattern", expected, choice_type); } const Value* parameter_types = FindInVarValues(alternative.AlternativeName(), cast(*choice_type).Alternatives()); if (parameter_types == nullptr) { - FATAL_COMPILATION_ERROR(alternative.LineNumber()) + FATAL_COMPILATION_ERROR(alternative.SourceLoc()) << "'" << alternative.AlternativeName() << "' is not an alternative of " << choice_type; } TCPattern arg_results = TypeCheckPattern(alternative.Arguments(), types, values, parameter_types); return {.pattern = global_arena->RawNew( - alternative.LineNumber(), - ReifyType(choice_type, alternative.LineNumber()), + alternative.SourceLoc(), + ReifyType(choice_type, alternative.SourceLoc()), alternative.AlternativeName(), cast(arg_results.pattern)), .type = choice_type, @@ -689,17 +691,17 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, ret_type, is_omitted_ret_type)); } const Statement* new_s = - global_arena->RawNew(s->LineNumber(), res.exp, new_clauses); + global_arena->RawNew(s->SourceLoc(), res.exp, new_clauses); return TCStatement(new_s, types); } case Statement::Kind::While: { const auto& while_stmt = cast(*s); auto cnd_res = TypeCheckExp(while_stmt.Cond(), types, values); - ExpectType(s->LineNumber(), "condition of `while`", + ExpectType(s->SourceLoc(), "condition of `while`", global_arena->RawNew(), cnd_res.type); auto body_res = TypeCheckStmt(while_stmt.Body(), types, values, ret_type, is_omitted_ret_type); - auto new_s = global_arena->RawNew(s->LineNumber(), cnd_res.exp, + auto new_s = global_arena->RawNew(s->SourceLoc(), cnd_res.exp, body_res.stmt); return TCStatement(new_s, types); } @@ -710,7 +712,7 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, auto stmt_res = TypeCheckStmt(cast(*s).Stmt(), types, values, ret_type, is_omitted_ret_type); return TCStatement( - global_arena->RawNew(s->LineNumber(), stmt_res.stmt), types); + global_arena->RawNew(s->SourceLoc(), stmt_res.stmt), types); } case Statement::Kind::VariableDefinition: { const auto& var = cast(*s); @@ -718,7 +720,7 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, const Value* rhs_ty = res.type; auto lhs_res = TypeCheckPattern(var.Pat(), types, values, rhs_ty); const Statement* new_s = global_arena->RawNew( - s->LineNumber(), var.Pat(), res.exp); + s->SourceLoc(), var.Pat(), res.exp); return TCStatement(new_s, lhs_res.types); } case Statement::Kind::Sequence: { @@ -730,7 +732,7 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, is_omitted_ret_type); auto types3 = next_res.types; return TCStatement(global_arena->RawNew( - s->LineNumber(), stmt_res.stmt, next_res.stmt), + s->SourceLoc(), stmt_res.stmt, next_res.stmt), types3); } case Statement::Kind::Assign: { @@ -739,8 +741,8 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, auto rhs_t = rhs_res.type; auto lhs_res = TypeCheckExp(assign.Lhs(), types, values); auto lhs_t = lhs_res.type; - ExpectType(s->LineNumber(), "assign", lhs_t, rhs_t); - auto new_s = global_arena->RawNew(s->LineNumber(), lhs_res.exp, + ExpectType(s->SourceLoc(), "assign", lhs_t, rhs_t); + auto new_s = global_arena->RawNew(s->SourceLoc(), lhs_res.exp, rhs_res.exp); return TCStatement(new_s, lhs_res.types); } @@ -748,19 +750,19 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, auto res = TypeCheckExp(cast(*s).Exp(), types, values); auto new_s = - global_arena->RawNew(s->LineNumber(), res.exp); + global_arena->RawNew(s->SourceLoc(), res.exp); return TCStatement(new_s, types); } case Statement::Kind::If: { const auto& if_stmt = cast(*s); auto cnd_res = TypeCheckExp(if_stmt.Cond(), types, values); - ExpectType(s->LineNumber(), "condition of `if`", + ExpectType(s->SourceLoc(), "condition of `if`", global_arena->RawNew(), cnd_res.type); auto then_res = TypeCheckStmt(if_stmt.ThenStmt(), types, values, ret_type, is_omitted_ret_type); auto else_res = TypeCheckStmt(if_stmt.ElseStmt(), types, values, ret_type, is_omitted_ret_type); - auto new_s = global_arena->RawNew(s->LineNumber(), cnd_res.exp, + auto new_s = global_arena->RawNew(s->SourceLoc(), cnd_res.exp, then_res.stmt, else_res.stmt); return TCStatement(new_s, types); } @@ -773,14 +775,14 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, // should infer the least-upper bound of all the 'return' statements. ret_type = res.type; } else { - ExpectType(s->LineNumber(), "return", ret_type, res.type); + ExpectType(s->SourceLoc(), "return", ret_type, res.type); } if (ret.IsOmittedExp() != is_omitted_ret_type) { - FATAL_COMPILATION_ERROR(s->LineNumber()) + FATAL_COMPILATION_ERROR(s->SourceLoc()) << *s << " should" << (is_omitted_ret_type ? " not" : "") << " provide a return value, to match the function's signature."; } - return TCStatement(global_arena->RawNew(s->LineNumber(), res.exp, + return TCStatement(global_arena->RawNew(s->SourceLoc(), res.exp, ret.IsOmittedExp()), types); } @@ -789,7 +791,7 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, TCStatement body_result = TypeCheckStmt(cont.Body(), types, values, ret_type, is_omitted_ret_type); const Statement* new_continuation = global_arena->RawNew( - s->LineNumber(), cont.ContinuationVariable(), body_result.stmt); + s->SourceLoc(), cont.ContinuationVariable(), body_result.stmt); types.Set(cont.ContinuationVariable(), global_arena->RawNew()); return TCStatement(new_continuation, types); @@ -797,11 +799,11 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, case Statement::Kind::Run: { TCExpression argument_result = TypeCheckExp(cast(*s).Argument(), types, values); - ExpectType(s->LineNumber(), "argument of `run`", + ExpectType(s->SourceLoc(), "argument of `run`", global_arena->RawNew(), argument_result.type); const Statement* new_run = - global_arena->RawNew(s->LineNumber(), argument_result.exp); + global_arena->RawNew(s->SourceLoc(), argument_result.exp); return TCStatement(new_run, types); } case Statement::Kind::Await: { @@ -812,13 +814,13 @@ auto TypeCheckStmt(const Statement* s, TypeEnv types, Env values, } static auto CheckOrEnsureReturn(const Statement* stmt, bool omitted_ret_type, - int line_num) -> const Statement* { + SourceLocation loc) -> const Statement* { if (!stmt) { if (omitted_ret_type) { - return global_arena->RawNew(line_num, nullptr, + return global_arena->RawNew(loc, nullptr, /*is_omitted_exp=*/true); } else { - FATAL_COMPILATION_ERROR(line_num) + FATAL_COMPILATION_ERROR(loc) << "control-flow reaches end of function that provides a `->` return " "type without reaching a return statement"; } @@ -830,25 +832,25 @@ static auto CheckOrEnsureReturn(const Statement* stmt, bool omitted_ret_type, std::list>>(); for (const auto& clause : *match.Clauses()) { auto s = CheckOrEnsureReturn(clause.second, omitted_ret_type, - stmt->LineNumber()); + stmt->SourceLoc()); new_clauses->push_back(std::make_pair(clause.first, s)); } - return global_arena->RawNew(stmt->LineNumber(), match.Exp(), + return global_arena->RawNew(stmt->SourceLoc(), match.Exp(), new_clauses); } case Statement::Kind::Block: return global_arena->RawNew( - stmt->LineNumber(), + stmt->SourceLoc(), CheckOrEnsureReturn(cast(*stmt).Stmt(), omitted_ret_type, - stmt->LineNumber())); + stmt->SourceLoc())); case Statement::Kind::If: { const auto& if_stmt = cast(*stmt); return global_arena->RawNew( - stmt->LineNumber(), if_stmt.Cond(), + stmt->SourceLoc(), if_stmt.Cond(), CheckOrEnsureReturn(if_stmt.ThenStmt(), omitted_ret_type, - stmt->LineNumber()), + stmt->SourceLoc()), CheckOrEnsureReturn(if_stmt.ElseStmt(), omitted_ret_type, - stmt->LineNumber())); + stmt->SourceLoc())); } case Statement::Kind::Return: return stmt; @@ -856,12 +858,12 @@ static auto CheckOrEnsureReturn(const Statement* stmt, bool omitted_ret_type, const auto& seq = cast(*stmt); if (seq.Next()) { return global_arena->RawNew( - stmt->LineNumber(), seq.Stmt(), + stmt->SourceLoc(), seq.Stmt(), CheckOrEnsureReturn(seq.Next(), omitted_ret_type, - stmt->LineNumber())); + stmt->SourceLoc())); } else { return CheckOrEnsureReturn(seq.Stmt(), omitted_ret_type, - stmt->LineNumber()); + stmt->SourceLoc()); } } case Statement::Kind::Continuation: @@ -876,11 +878,11 @@ static auto CheckOrEnsureReturn(const Statement* stmt, bool omitted_ret_type, case Statement::Kind::VariableDefinition: if (omitted_ret_type) { return global_arena->RawNew( - stmt->LineNumber(), stmt, - global_arena->RawNew(line_num, nullptr, + stmt->SourceLoc(), stmt, + global_arena->RawNew(loc, nullptr, /*is_omitted_exp=*/true)); } else { - FATAL_COMPILATION_ERROR(stmt->LineNumber()) + FATAL_COMPILATION_ERROR(stmt->SourceLoc()) << "control-flow reaches end of function that provides a `->` " "return type without reaching a return statement"; } @@ -905,18 +907,18 @@ static auto TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, // Evaluate the return type expression auto return_type = InterpPattern(values, f->return_type); if (f->name == "main") { - ExpectType(f->line_num, "return type of `main`", + ExpectType(f->source_location, "return type of `main`", global_arena->RawNew(), return_type); // TODO: Check that main doesn't have any parameters. } auto res = TypeCheckStmt(f->body, param_res.types, values, return_type, f->is_omitted_return_type); - auto body = - CheckOrEnsureReturn(res.stmt, f->is_omitted_return_type, f->line_num); + auto body = CheckOrEnsureReturn(res.stmt, f->is_omitted_return_type, + f->source_location); return global_arena->New( - f->line_num, f->name, f->deduced_parameters, f->param_pattern, + f->source_location, f->name, f->deduced_parameters, f->param_pattern, global_arena->RawNew( - ReifyType(return_type, f->line_num)), + ReifyType(return_type, f->source_location)), /*is_omitted_return_type=*/false, body); } @@ -951,13 +953,13 @@ static auto TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/, case Member::Kind::FieldMember: { const BindingPattern* binding = cast(*m).Binding(); if (!binding->Name().has_value()) { - FATAL_COMPILATION_ERROR(binding->LineNumber()) + FATAL_COMPILATION_ERROR(binding->SourceLoc()) << "Struct members must have names"; } const Expression* type_expression = dyn_cast(binding->Type())->Expression(); if (type_expression == nullptr) { - FATAL_COMPILATION_ERROR(binding->LineNumber()) + FATAL_COMPILATION_ERROR(binding->SourceLoc()) << "Struct members must have explicit types"; } auto type = InterpExp(ct_top, type_expression); @@ -981,7 +983,7 @@ static auto GetName(const Declaration& d) -> const std::string& { case Declaration::Kind::VariableDeclaration: { const BindingPattern* binding = cast(d).Binding(); if (!binding->Name().has_value()) { - FATAL_COMPILATION_ERROR(binding->LineNumber()) + FATAL_COMPILATION_ERROR(binding->SourceLoc()) << "Top-level variable declarations must have names"; } return *binding->Name(); @@ -1008,8 +1010,8 @@ auto MakeTypeChecked(const Ptr d, const TypeEnv& types, break; } } - return global_arena->New( - class_def.line_num, class_def.name, std::move(fields)); + return global_arena->New(class_def.loc, class_def.name, + std::move(fields)); } case Declaration::Kind::ChoiceDeclaration: @@ -1027,11 +1029,11 @@ auto MakeTypeChecked(const Ptr d, const TypeEnv& types, dyn_cast(var.Binding()->Type())->Expression(); if (type == nullptr) { // TODO: consider adding support for `auto` - FATAL_COMPILATION_ERROR(var.LineNumber()) + FATAL_COMPILATION_ERROR(var.SourceLoc()) << "Type of a top-level variable must be an expression."; } const Value* declared_type = InterpExp(values, type); - ExpectType(var.LineNumber(), "initializer of variable", declared_type, + ExpectType(var.SourceLoc(), "initializer of variable", declared_type, type_checked_initializer.type); return d; } diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index d3ca97707a64..afee2b72b646 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -54,29 +54,28 @@ auto TupleValue::FindField(const std::string& name) const -> const Value* { namespace { -auto GetMember(const Value* v, const std::string& f, int line_num) +auto GetMember(const Value* v, const std::string& f, SourceLocation loc) -> const Value* { switch (v->Tag()) { case Value::Kind::StructValue: { const Value* field = cast(*cast(*v).Inits()).FindField(f); if (field == nullptr) { - FATAL_RUNTIME_ERROR(line_num) << "member " << f << " not in " << *v; + FATAL_RUNTIME_ERROR(loc) << "member " << f << " not in " << *v; } return field; } case Value::Kind::TupleValue: { const Value* field = cast(*v).FindField(f); if (field == nullptr) { - FATAL_RUNTIME_ERROR(line_num) << "field " << f << " not in " << *v; + FATAL_RUNTIME_ERROR(loc) << "field " << f << " not in " << *v; } return field; } case Value::Kind::ChoiceType: { const auto& choice = cast(*v); if (FindInVarValues(f, choice.Alternatives()) == nullptr) { - FATAL_RUNTIME_ERROR(line_num) - << "alternative " << f << " not in " << *v; + FATAL_RUNTIME_ERROR(loc) << "alternative " << f << " not in " << *v; } return global_arena->RawNew(f, choice.Name()); @@ -88,11 +87,11 @@ auto GetMember(const Value* v, const std::string& f, int line_num) } // namespace -auto Value::GetField(const FieldPath& path, int line_num) const +auto Value::GetField(const FieldPath& path, SourceLocation loc) const -> const Value* { const Value* value = this; for (const std::string& field : path.components) { - value = GetMember(value, field, line_num); + value = GetMember(value, field, loc); } return value; } @@ -102,14 +101,15 @@ namespace { auto SetFieldImpl(const Value* value, std::vector::const_iterator path_begin, std::vector::const_iterator path_end, - const Value* field_value, int line_num) -> const Value* { + const Value* field_value, SourceLocation loc) + -> const Value* { if (path_begin == path_end) { return field_value; } switch (value->Tag()) { case Value::Kind::StructValue: { return SetFieldImpl(cast(*value).Inits(), path_begin, - path_end, field_value, line_num); + path_end, field_value, loc); } case Value::Kind::TupleValue: { std::vector elements = cast(*value).Elements(); @@ -118,11 +118,11 @@ auto SetFieldImpl(const Value* value, return element.name == *path_begin; }); if (it == elements.end()) { - FATAL_RUNTIME_ERROR(line_num) + FATAL_RUNTIME_ERROR(loc) << "field " << *path_begin << " not in " << *value; } - it->value = SetFieldImpl(it->value, path_begin + 1, path_end, field_value, - line_num); + it->value = + SetFieldImpl(it->value, path_begin + 1, path_end, field_value, loc); return global_arena->RawNew(elements); } default: @@ -133,9 +133,9 @@ auto SetFieldImpl(const Value* value, } // namespace auto Value::SetField(const FieldPath& path, const Value* field_value, - int line_num) const -> const Value* { + SourceLocation loc) const -> const Value* { return SetFieldImpl(this, path.components.begin(), path.components.end(), - field_value, line_num); + field_value, loc); } void Value::Print(llvm::raw_ostream& out) const { @@ -248,25 +248,25 @@ void Value::Print(llvm::raw_ostream& out) const { } } -auto CopyVal(const Value* val, int line_num) -> const Value* { +auto CopyVal(const Value* val, SourceLocation loc) -> const Value* { switch (val->Tag()) { case Value::Kind::TupleValue: { std::vector elements; for (const TupleElement& element : cast(*val).Elements()) { elements.push_back( - {.name = element.name, .value = CopyVal(element.value, line_num)}); + {.name = element.name, .value = CopyVal(element.value, loc)}); } return global_arena->RawNew(std::move(elements)); } case Value::Kind::AlternativeValue: { const auto& alt = cast(*val); - const Value* arg = CopyVal(alt.Argument(), line_num); + const Value* arg = CopyVal(alt.Argument(), loc); return global_arena->RawNew(alt.AltName(), alt.ChoiceName(), arg); } case Value::Kind::StructValue: { const auto& s = cast(*val); - const Value* inits = CopyVal(s.Inits(), line_num); + const Value* inits = CopyVal(s.Inits(), loc); return global_arena->RawNew(s.Type(), inits); } case Value::Kind::IntValue: @@ -285,13 +285,13 @@ auto CopyVal(const Value* val, int line_num) -> const Value* { return val; case Value::Kind::FunctionType: { const auto& fn_type = cast(*val); - return global_arena->RawNew( - fn_type.Deduced(), CopyVal(fn_type.Param(), line_num), - CopyVal(fn_type.Ret(), line_num)); + return global_arena->RawNew(fn_type.Deduced(), + CopyVal(fn_type.Param(), loc), + CopyVal(fn_type.Ret(), loc)); } case Value::Kind::PointerType: return global_arena->RawNew( - CopyVal(cast(*val).Type(), line_num)); + CopyVal(cast(*val).Type(), loc)); case Value::Kind::IntType: return global_arena->RawNew(); case Value::Kind::BoolType: @@ -366,8 +366,8 @@ auto TypeEqual(const Value* t1, const Value* t2) -> bool { // Returns true if all the fields of the two tuples contain equal values // and returns false otherwise. static auto FieldsValueEqual(const std::vector& ts1, - const std::vector& ts2, int line_num) - -> bool { + const std::vector& ts2, + SourceLocation loc) -> bool { if (ts1.size() != ts2.size()) { return false; } @@ -378,7 +378,7 @@ static auto FieldsValueEqual(const std::vector& ts1, if (iter == ts2.end()) { return false; } - if (!ValueEqual(element.value, iter->value, line_num)) { + if (!ValueEqual(element.value, iter->value, loc)) { return false; } } @@ -388,7 +388,7 @@ static auto FieldsValueEqual(const std::vector& ts1, // Returns true if the two values are equal and returns false otherwise. // // This function implements the `==` operator of Carbon. -auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool { +auto ValueEqual(const Value* v1, const Value* v2, SourceLocation loc) -> bool { if (v1->Tag() != v2->Tag()) { return false; } @@ -403,7 +403,7 @@ auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool { return cast(*v1).Body() == cast(*v2).Body(); case Value::Kind::TupleValue: return FieldsValueEqual(cast(*v1).Elements(), - cast(*v2).Elements(), line_num); + cast(*v2).Elements(), loc); case Value::Kind::StringValue: return cast(*v1).Val() == cast(*v2).Val(); case Value::Kind::IntType: diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index 278124307057..ea1d1ec0f4ff 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -69,12 +69,13 @@ class Value { // Returns the sub-Value specified by `path`, which must be a valid field // path for *this. - auto GetField(const FieldPath& path, int line_num) const -> const Value*; + auto GetField(const FieldPath& path, SourceLocation loc) const + -> const Value*; // Returns a copy of *this, but with the sub-Value specified by `path` // set to `field_value`. `path` must be a valid field path for *this. auto SetField(const FieldPath& path, const Value* field_value, - int line_num) const -> const Value*; + SourceLocation loc) const -> const Value*; protected: // Constructs a Value. `tag` must be the enumerator corresponding to the @@ -471,10 +472,10 @@ class StringValue : public Value { std::string val; }; -auto CopyVal(const Value* val, int line_num) -> const Value*; +auto CopyVal(const Value* val, SourceLocation loc) -> const Value*; auto TypeEqual(const Value* t1, const Value* t2) -> bool; -auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool; +auto ValueEqual(const Value* v1, const Value* v2, SourceLocation loc) -> bool; } // namespace Carbon diff --git a/executable_semantics/syntax/parse_and_lex_context.cpp b/executable_semantics/syntax/parse_and_lex_context.cpp index dd0c61346fc8..a141c2b2eb0b 100644 --- a/executable_semantics/syntax/parse_and_lex_context.cpp +++ b/executable_semantics/syntax/parse_and_lex_context.cpp @@ -6,14 +6,11 @@ namespace Carbon { -// Writes a syntax error diagnostic, containing message, for the input file at -// the given line, to standard error. -auto ParseAndLexContext::PrintDiagnostic(const std::string& message, - int line_num) -> void { +auto ParseAndLexContext::PrintDiagnostic(const std::string& message) -> void { // TODO: Do we really want this to be fatal? It makes the comment and the // name a lie, and renders some of the other yyparse() result propagation code // moot. - FATAL_COMPILATION_ERROR(line_num) << message; + FATAL_COMPILATION_ERROR(SourceLoc()) << message; } } // namespace Carbon diff --git a/executable_semantics/syntax/parse_and_lex_context.h b/executable_semantics/syntax/parse_and_lex_context.h index 4ada19eb4463..658fdeea7008 100644 --- a/executable_semantics/syntax/parse_and_lex_context.h +++ b/executable_semantics/syntax/parse_and_lex_context.h @@ -18,11 +18,15 @@ class ParseAndLexContext { public: // Creates an instance analyzing the given input file. ParseAndLexContext(const std::string& input_file) - : input_file_name(input_file) {} + : input_file_name(global_arena->New(input_file)) {} - // Writes a syntax error diagnostic, containing message, for the input file at - // the given line, to standard error. - auto PrintDiagnostic(const std::string& message, int line_number) -> void; + // Writes a syntax error diagnostic containing message to standard error. + auto PrintDiagnostic(const std::string& message) -> void; + + auto SourceLoc() -> SourceLocation { + return SourceLocation(input_file_name, + static_cast(current_token_position.begin.line)); + } // The source range of the token being (or just) lex'd. location current_token_position; @@ -30,7 +34,7 @@ class ParseAndLexContext { private: // A path to the file processed, relative to the current working directory // when *this is called. - const std::string input_file_name; + Ptr input_file_name; }; } // namespace Carbon diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index d1690a6ce895..f35001d6d63a 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -81,10 +81,8 @@ class ParseAndLexContext; %code { -extern int yylineno; - void Carbon::Parser::error(const location_type&, const std::string& message) { - context.PrintDiagnostic(message, yylineno); + context.PrintDiagnostic(message); } } // %code @@ -215,84 +213,84 @@ input: declaration_list ; expression: identifier - { $$ = global_arena->RawNew(yylineno, $1); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1); } | expression designator - { $$ = global_arena->RawNew(yylineno, $1, $2); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1, $2); } | expression "[" expression "]" - { $$ = global_arena->RawNew(yylineno, $1, $3); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1, $3); } | integer_literal - { $$ = global_arena->RawNew(yylineno, $1); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1); } | string_literal - { $$ = global_arena->RawNew(yylineno, $1); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1); } | TRUE - { $$ = global_arena->RawNew(yylineno, true); } + { $$ = global_arena->RawNew(context.SourceLoc(), true); } | FALSE - { $$ = global_arena->RawNew(yylineno, false); } + { $$ = global_arena->RawNew(context.SourceLoc(), false); } | sized_type_literal { int val; CHECK(llvm::to_integer(llvm::StringRef($1).substr(1), val)); CHECK($1[0] == 'i' && val == 32) << "Only i32 is supported for now: " << $1; - $$ = global_arena->RawNew(yylineno); + $$ = global_arena->RawNew(context.SourceLoc()); } | STRING - { $$ = global_arena->RawNew(yylineno); } + { $$ = global_arena->RawNew(context.SourceLoc()); } | BOOL - { $$ = global_arena->RawNew(yylineno); } + { $$ = global_arena->RawNew(context.SourceLoc()); } | TYPE - { $$ = global_arena->RawNew(yylineno); } + { $$ = global_arena->RawNew(context.SourceLoc()); } | CONTINUATION_TYPE - { $$ = global_arena->RawNew(yylineno); } + { $$ = global_arena->RawNew(context.SourceLoc()); } | paren_expression { $$ = $1; } | expression EQUAL_EQUAL expression { $$ = global_arena->RawNew( - yylineno, Operator::Eq, std::vector({$1, $3})); } + context.SourceLoc(), Operator::Eq, std::vector({$1, $3})); } | expression "+" expression { $$ = global_arena->RawNew( - yylineno, Operator::Add, std::vector({$1, $3})); } + context.SourceLoc(), Operator::Add, std::vector({$1, $3})); } | expression "-" expression { $$ = global_arena->RawNew( - yylineno, Operator::Sub, std::vector({$1, $3})); } + context.SourceLoc(), Operator::Sub, std::vector({$1, $3})); } | expression BINARY_STAR expression { $$ = global_arena->RawNew( - yylineno, Operator::Mul, std::vector({$1, $3})); } + context.SourceLoc(), Operator::Mul, std::vector({$1, $3})); } | expression AND expression { $$ = global_arena->RawNew( - yylineno, Operator::And, std::vector({$1, $3})); } + context.SourceLoc(), Operator::And, std::vector({$1, $3})); } | expression OR expression { $$ = global_arena->RawNew( - yylineno, Operator::Or, std::vector({$1, $3})); } + context.SourceLoc(), Operator::Or, std::vector({$1, $3})); } | NOT expression { $$ = global_arena->RawNew( - yylineno, Operator::Not, std::vector({$2})); } + context.SourceLoc(), Operator::Not, std::vector({$2})); } | "-" expression %prec UNARY_MINUS { $$ = global_arena->RawNew( - yylineno, Operator::Neg, std::vector({$2})); } + context.SourceLoc(), Operator::Neg, std::vector({$2})); } | PREFIX_STAR expression { $$ = global_arena->RawNew( - yylineno, Operator::Deref, std::vector({$2})); } + context.SourceLoc(), Operator::Deref, std::vector({$2})); } | UNARY_STAR expression %prec PREFIX_STAR { $$ = global_arena->RawNew( - yylineno, Operator::Deref, std::vector({$2})); } + context.SourceLoc(), Operator::Deref, std::vector({$2})); } | expression tuple - { $$ = global_arena->RawNew(yylineno, $1, $2); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1, $2); } | expression POSTFIX_STAR { $$ = global_arena->RawNew( - yylineno, Operator::Ptr, std::vector({$1})); } + context.SourceLoc(), Operator::Ptr, std::vector({$1})); } | expression UNARY_STAR { $$ = global_arena->RawNew( - yylineno, Operator::Ptr, std::vector({$1})); } + context.SourceLoc(), Operator::Ptr, std::vector({$1})); } | FNTY tuple return_type { $$ = global_arena->RawNew( - yylineno, $2, $3.first, $3.second); } + context.SourceLoc(), $2, $3.first, $3.second); } ; designator: "." identifier { $$ = $2; } ; paren_expression: paren_expression_base - { $$ = ExpressionFromParenContents(yylineno, $1); } + { $$ = ExpressionFromParenContents(context.SourceLoc(), $1); } ; tuple: paren_expression_base - { $$ = TupleExpressionFromParenContents(yylineno, $1); } + { $$ = TupleExpressionFromParenContents(context.SourceLoc(), $1); } ; paren_expression_element: expression @@ -335,20 +333,20 @@ pattern: ; non_expression_pattern: AUTO - { $$ = global_arena->RawNew(yylineno); } + { $$ = global_arena->RawNew(context.SourceLoc()); } | binding_lhs ":" pattern - { $$ = global_arena->RawNew(yylineno, $1, $3); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1, $3); } | paren_pattern { $$ = $1; } | expression tuple_pattern - { $$ = global_arena->RawNew(yylineno, $1, $2); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1, $2); } ; binding_lhs: identifier { $$ = $1; } | UNDERSCORE { $$ = std::nullopt; } ; paren_pattern: paren_pattern_base - { $$ = PatternFromParenContents(yylineno, $1); } + { $$ = PatternFromParenContents(context.SourceLoc(), $1); } ; paren_pattern_base: "(" paren_pattern_contents ")" @@ -390,14 +388,14 @@ paren_pattern_element: { $$ = {.name = $1, .term = $3}; } ; tuple_pattern: paren_pattern_base - { $$ = TuplePatternFromParenContents(yylineno, $1); } + { $$ = TuplePatternFromParenContents(context.SourceLoc(), $1); } ; // Unlike most `pattern` nonterminals, this one overlaps with `expression`, // so it should be used only when prior context (such as an introducer) // rules out the possibility of an `expression` at this point. maybe_empty_tuple_pattern: "(" ")" - { $$ = global_arena->RawNew(yylineno, std::vector()); } + { $$ = global_arena->RawNew(context.SourceLoc(), std::vector()); } | tuple_pattern { $$ = $1; } ; @@ -407,7 +405,7 @@ clause: | DEFAULT DBLARROW statement { auto vp = global_arena->RawNew( - yylineno, std::nullopt, global_arena->RawNew(yylineno)); + context.SourceLoc(), std::nullopt, global_arena->RawNew(context.SourceLoc())); $$ = global_arena->RawNew>(vp, $3); } ; @@ -422,35 +420,35 @@ clause_list: ; statement: expression "=" expression ";" - { $$ = global_arena->RawNew(yylineno, $1, $3); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1, $3); } | VAR pattern "=" expression ";" - { $$ = global_arena->RawNew(yylineno, $2, $4); } + { $$ = global_arena->RawNew(context.SourceLoc(), $2, $4); } | expression ";" - { $$ = global_arena->RawNew(yylineno, $1); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1); } | if_statement { $$ = $1; } | WHILE "(" expression ")" block - { $$ = global_arena->RawNew(yylineno, $3, $5); } + { $$ = global_arena->RawNew(context.SourceLoc(), $3, $5); } | BREAK ";" - { $$ = global_arena->RawNew(yylineno); } + { $$ = global_arena->RawNew(context.SourceLoc()); } | CONTINUE ";" - { $$ = global_arena->RawNew(yylineno); } + { $$ = global_arena->RawNew(context.SourceLoc()); } | RETURN return_expression ";" - { $$ = global_arena->RawNew(yylineno, $2.first, $2.second); } + { $$ = global_arena->RawNew(context.SourceLoc(), $2.first, $2.second); } | block { $$ = $1; } | MATCH "(" expression ")" "{" clause_list "}" - { $$ = global_arena->RawNew(yylineno, $3, $6); } + { $$ = global_arena->RawNew(context.SourceLoc(), $3, $6); } | CONTINUATION identifier statement - { $$ = global_arena->RawNew(yylineno, $2, $3); } + { $$ = global_arena->RawNew(context.SourceLoc(), $2, $3); } | RUN expression ";" - { $$ = global_arena->RawNew(yylineno, $2); } + { $$ = global_arena->RawNew(context.SourceLoc(), $2); } | AWAIT ";" - { $$ = global_arena->RawNew(yylineno); } + { $$ = global_arena->RawNew(context.SourceLoc()); } ; if_statement: IF "(" expression ")" block optional_else - { $$ = global_arena->RawNew(yylineno, $3, $5, $6); } + { $$ = global_arena->RawNew(context.SourceLoc(), $3, $5, $6); } ; optional_else: // Empty @@ -462,7 +460,7 @@ optional_else: ; return_expression: // Empty - { $$ = {global_arena->RawNew(yylineno), true}; } + { $$ = {global_arena->RawNew(context.SourceLoc()), true}; } | expression { $$ = {$1, false}; } ; @@ -470,15 +468,15 @@ statement_list: // Empty { $$ = 0; } | statement statement_list - { $$ = global_arena->RawNew(yylineno, $1, $2); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1, $2); } ; block: "{" statement_list "}" - { $$ = global_arena->RawNew(yylineno, $2); } + { $$ = global_arena->RawNew(context.SourceLoc(), $2); } ; return_type: // Empty - { $$ = {global_arena->RawNew(yylineno), true}; } + { $$ = {global_arena->RawNew(context.SourceLoc()), true}; } | ARROW expression %prec FNARROW { $$ = {$2, false}; } ; @@ -512,7 +510,7 @@ function_definition: FN identifier deduced_params maybe_empty_tuple_pattern return_type block { $$ = global_arena->New( - yylineno, $2, $3, $4, + context.SourceLoc(), $2, $3, $4, global_arena->RawNew($5.first), $5.second, $6); } @@ -521,24 +519,24 @@ function_definition: // The return type is not considered "omitted" because it's automatic from // the expression. $$ = global_arena->New( - yylineno, $2, $3, $4, - global_arena->RawNew(yylineno), true, - global_arena->RawNew(yylineno, $6, true)); + context.SourceLoc(), $2, $3, $4, + global_arena->RawNew(context.SourceLoc()), true, + global_arena->RawNew(context.SourceLoc(), $6, true)); } ; function_declaration: FN identifier deduced_params maybe_empty_tuple_pattern return_type ";" { $$ = global_arena->New( - yylineno, $2, $3, $4, + context.SourceLoc(), $2, $3, $4, global_arena->RawNew($5.first), $5.second, nullptr); } ; variable_declaration: identifier ":" pattern - { $$ = global_arena->RawNew(yylineno, $1, $3); } + { $$ = global_arena->RawNew(context.SourceLoc(), $1, $3); } ; member: VAR variable_declaration ";" - { $$ = global_arena->RawNew(yylineno, $2); } + { $$ = global_arena->RawNew(context.SourceLoc(), $2); } ; member_list: // Empty @@ -552,7 +550,7 @@ alternative: | identifier { $$ = std::pair( - $1, global_arena->RawNew(yylineno)); + $1, global_arena->RawNew(context.SourceLoc())); } ; alternative_list: @@ -573,15 +571,15 @@ declaration: { $$ = global_arena->New($1); } | CLASS identifier "{" member_list "}" { - $$ = global_arena->New(yylineno, $2, $4); + $$ = global_arena->New(context.SourceLoc(), $2, $4); } | CHOICE identifier "{" alternative_list "}" { - $$ = global_arena->New(yylineno, $2, $4); + $$ = global_arena->New(context.SourceLoc(), $2, $4); } | VAR variable_declaration "=" expression ";" { - $$ = global_arena->New(yylineno, $2, $4); + $$ = global_arena->New(context.SourceLoc(), $2, $4); } ; declaration_list: diff --git a/executable_semantics/syntax/syntax_helpers.cpp b/executable_semantics/syntax/syntax_helpers.cpp index 728e31ec2999..9f0e011c02f4 100644 --- a/executable_semantics/syntax/syntax_helpers.cpp +++ b/executable_semantics/syntax/syntax_helpers.cpp @@ -16,22 +16,23 @@ namespace Carbon { // Adds builtins, currently only Print(). Note Print() is experimental, not // standardized, but is made available for printing state in tests. static void AddIntrinsics(std::list>* fs) { + SourceLocation loc("", 0); std::vector print_fields = {TuplePattern::Field( "0", global_arena->RawNew( - -1, "format_str", + loc, "format_str", global_arena->RawNew( - global_arena->RawNew(-1))))}; + global_arena->RawNew(loc))))}; auto* print_return = global_arena->RawNew( - -1, + loc, global_arena->RawNew( IntrinsicExpression::IntrinsicKind::Print), false); auto print = global_arena->New( global_arena->New( - -1, "Print", std::vector(), - global_arena->RawNew(-1, print_fields), + loc, "Print", std::vector(), + global_arena->RawNew(loc, print_fields), global_arena->RawNew( - global_arena->RawNew(-1)), + global_arena->RawNew(loc)), /*is_omitted_return_type=*/false, print_return)); fs->insert(fs->begin(), print); } diff --git a/executable_semantics/testdata/class_field_access_mismatch.golden b/executable_semantics/testdata/class_field_access_mismatch.golden index 87d8c65583d0..30a5f60a5b24 100644 --- a/executable_semantics/testdata/class_field_access_mismatch.golden +++ b/executable_semantics/testdata/class_field_access_mismatch.golden @@ -1,2 +1,2 @@ -COMPILATION ERROR: 11: class Point does not have a field named z +COMPILATION ERROR: executable_semantics/testdata/class_field_access_mismatch.carbon:11: class Point does not have a field named z EXIT CODE: 255 diff --git a/executable_semantics/testdata/class_field_mismatch.golden b/executable_semantics/testdata/class_field_mismatch.golden index 6f8e2d2ffd7b..188dd1f33297 100644 --- a/executable_semantics/testdata/class_field_mismatch.golden +++ b/executable_semantics/testdata/class_field_mismatch.golden @@ -1,4 +1,4 @@ -COMPILATION ERROR: 11: type error in call +COMPILATION ERROR: executable_semantics/testdata/class_field_mismatch.carbon:11: type error in call expected: (x = i32, y = i32) actual: (x = i32, z = i32) EXIT CODE: 255 diff --git a/executable_semantics/testdata/class_field_missing.golden b/executable_semantics/testdata/class_field_missing.golden index 1131c8186595..cf1731d6af4a 100644 --- a/executable_semantics/testdata/class_field_missing.golden +++ b/executable_semantics/testdata/class_field_missing.golden @@ -1,4 +1,4 @@ -COMPILATION ERROR: 11: type error in call +COMPILATION ERROR: executable_semantics/testdata/class_field_missing.carbon:11: type error in call expected: (x = i32, y = i32) actual: (x = i32) EXIT CODE: 255 diff --git a/executable_semantics/testdata/experimental_continuation9.golden b/executable_semantics/testdata/experimental_continuation9.golden index 69f6f8a427eb..c5c9dcf99c2f 100644 --- a/executable_semantics/testdata/experimental_continuation9.golden +++ b/executable_semantics/testdata/experimental_continuation9.golden @@ -1,2 +1,2 @@ -RUNTIME ERROR: 12: undefined behavior: access to dead value 1 +RUNTIME ERROR: executable_semantics/testdata/experimental_continuation9.carbon:12: undefined behavior: access to dead value 1 EXIT CODE: 255 diff --git a/executable_semantics/testdata/fun6_fail_type.golden b/executable_semantics/testdata/fun6_fail_type.golden index 6182f1b90379..9e826ffdfe26 100644 --- a/executable_semantics/testdata/fun6_fail_type.golden +++ b/executable_semantics/testdata/fun6_fail_type.golden @@ -1,4 +1,4 @@ -COMPILATION ERROR: 10: type error in call +COMPILATION ERROR: executable_semantics/testdata/fun6_fail_type.carbon:10: type error in call expected: (0 = i32, 1 = i32) actual: (0 = (0 = i32, 1 = i32)) EXIT CODE: 255 diff --git a/executable_semantics/testdata/fun_named_params2.golden b/executable_semantics/testdata/fun_named_params2.golden index 3364177cf3e6..5c2e78c66a66 100644 --- a/executable_semantics/testdata/fun_named_params2.golden +++ b/executable_semantics/testdata/fun_named_params2.golden @@ -1,2 +1,2 @@ -PROGRAM ERROR: 5: positional members must come before named members +PROGRAM ERROR: executable_semantics/testdata/fun_named_params2.carbon:5: positional members must come before named members EXIT CODE: 255 diff --git a/executable_semantics/testdata/generic_function_fail1.golden b/executable_semantics/testdata/generic_function_fail1.golden index c3d6a6dc1ca6..01745cfd1b18 100644 --- a/executable_semantics/testdata/generic_function_fail1.golden +++ b/executable_semantics/testdata/generic_function_fail1.golden @@ -1,4 +1,4 @@ -COMPILATION ERROR: 10: type error in argument deduction +COMPILATION ERROR: executable_semantics/testdata/generic_function_fail1.carbon:10: type error in argument deduction expected: i32 actual: Bool EXIT CODE: 255 diff --git a/executable_semantics/testdata/generic_function_fail2.golden b/executable_semantics/testdata/generic_function_fail2.golden index e68f10f041f9..42d085b1b195 100644 --- a/executable_semantics/testdata/generic_function_fail2.golden +++ b/executable_semantics/testdata/generic_function_fail2.golden @@ -1,2 +1,2 @@ -COMPILATION ERROR: 10: could not deduce type argument for type parameter T +COMPILATION ERROR: executable_semantics/testdata/generic_function_fail2.carbon:10: could not deduce type argument for type parameter T EXIT CODE: 255 diff --git a/executable_semantics/testdata/generic_function_fail3.golden b/executable_semantics/testdata/generic_function_fail3.golden index e39634c5ccdd..58eac0b6c775 100644 --- a/executable_semantics/testdata/generic_function_fail3.golden +++ b/executable_semantics/testdata/generic_function_fail3.golden @@ -1,4 +1,4 @@ -COMPILATION ERROR: 6: type error in addition(1) +COMPILATION ERROR: executable_semantics/testdata/generic_function_fail3.carbon:6: type error in addition(1) expected: i32 actual: T EXIT CODE: 255 diff --git a/executable_semantics/testdata/global_variable3.golden b/executable_semantics/testdata/global_variable3.golden index 6b4a374ede66..4d773e7732ce 100644 --- a/executable_semantics/testdata/global_variable3.golden +++ b/executable_semantics/testdata/global_variable3.golden @@ -1,4 +1,4 @@ -COMPILATION ERROR: 7: type error in initializer of variable +COMPILATION ERROR: executable_semantics/testdata/global_variable3.carbon:7: type error in initializer of variable expected: i32 actual: Bool EXIT CODE: 255 diff --git a/executable_semantics/testdata/global_variable5.golden b/executable_semantics/testdata/global_variable5.golden index 73323db83507..46bbc5460136 100644 --- a/executable_semantics/testdata/global_variable5.golden +++ b/executable_semantics/testdata/global_variable5.golden @@ -1,4 +1,4 @@ -COMPILATION ERROR: 10: type error in return +COMPILATION ERROR: executable_semantics/testdata/global_variable5.carbon:10: type error in return expected: () actual: i32 EXIT CODE: 255 diff --git a/executable_semantics/testdata/global_variable8.golden b/executable_semantics/testdata/global_variable8.golden index 4c4931084369..6ea3a1dba1cc 100644 --- a/executable_semantics/testdata/global_variable8.golden +++ b/executable_semantics/testdata/global_variable8.golden @@ -1,2 +1,2 @@ -RUNTIME ERROR: 8: could not find `y` +RUNTIME ERROR: executable_semantics/testdata/global_variable8.carbon:8: could not find `y` EXIT CODE: 255 diff --git a/executable_semantics/testdata/pattern_variable_fail.golden b/executable_semantics/testdata/pattern_variable_fail.golden index 6ed738177b7a..072f39175f24 100644 --- a/executable_semantics/testdata/pattern_variable_fail.golden +++ b/executable_semantics/testdata/pattern_variable_fail.golden @@ -1,2 +1,2 @@ -COMPILATION ERROR: 7: syntax error, unexpected : +COMPILATION ERROR: executable_semantics/testdata/pattern_variable_fail.carbon:7: syntax error, unexpected : EXIT CODE: 255 diff --git a/executable_semantics/testdata/return_auto.golden b/executable_semantics/testdata/return_auto.golden index 2e501a90e861..af691c27f45a 100644 --- a/executable_semantics/testdata/return_auto.golden +++ b/executable_semantics/testdata/return_auto.golden @@ -1,2 +1,2 @@ -COMPILATION ERROR: 5: syntax error, unexpected AUTO +COMPILATION ERROR: executable_semantics/testdata/return_auto.carbon:5: syntax error, unexpected AUTO EXIT CODE: 255 diff --git a/executable_semantics/testdata/return_empty_explicit_fail.golden b/executable_semantics/testdata/return_empty_explicit_fail.golden index 6a0a1b4c8694..ffb01fe18414 100644 --- a/executable_semantics/testdata/return_empty_explicit_fail.golden +++ b/executable_semantics/testdata/return_empty_explicit_fail.golden @@ -1,2 +1,2 @@ -COMPILATION ERROR: 6: return (); should not provide a return value, to match the function's signature. +COMPILATION ERROR: executable_semantics/testdata/return_empty_explicit_fail.carbon:6: return (); should not provide a return value, to match the function's signature. EXIT CODE: 255 diff --git a/executable_semantics/testdata/return_empty_implicit_fail1.golden b/executable_semantics/testdata/return_empty_implicit_fail1.golden index ba4df5083431..70cc48626543 100644 --- a/executable_semantics/testdata/return_empty_implicit_fail1.golden +++ b/executable_semantics/testdata/return_empty_implicit_fail1.golden @@ -1,2 +1,2 @@ -COMPILATION ERROR: 6: control-flow reaches end of function that provides a `->` return type without reaching a return statement +COMPILATION ERROR: executable_semantics/testdata/return_empty_implicit_fail1.carbon:6: control-flow reaches end of function that provides a `->` return type without reaching a return statement EXIT CODE: 255 diff --git a/executable_semantics/testdata/return_empty_implicit_fail2.golden b/executable_semantics/testdata/return_empty_implicit_fail2.golden index f5a8406f4482..d0e0e17d94a9 100644 --- a/executable_semantics/testdata/return_empty_implicit_fail2.golden +++ b/executable_semantics/testdata/return_empty_implicit_fail2.golden @@ -1,2 +1,2 @@ -COMPILATION ERROR: 6: return; should provide a return value, to match the function's signature. +COMPILATION ERROR: executable_semantics/testdata/return_empty_implicit_fail2.carbon:6: return; should provide a return value, to match the function's signature. EXIT CODE: 255 diff --git a/executable_semantics/testdata/tuple4.golden b/executable_semantics/testdata/tuple4.golden index 76fdf961c933..6d03bdae31f7 100644 --- a/executable_semantics/testdata/tuple4.golden +++ b/executable_semantics/testdata/tuple4.golden @@ -1,2 +1,2 @@ -PROGRAM ERROR: 6: positional members must come before named members +PROGRAM ERROR: executable_semantics/testdata/tuple4.carbon:6: positional members must come before named members EXIT CODE: 255 diff --git a/executable_semantics/testdata/tuple5.golden b/executable_semantics/testdata/tuple5.golden index c3d14dc94826..4860ba283c5d 100644 --- a/executable_semantics/testdata/tuple5.golden +++ b/executable_semantics/testdata/tuple5.golden @@ -1,2 +1,2 @@ -PROGRAM ERROR: 8: Tuple field name 'y' does not match pattern field name 'x' +PROGRAM ERROR: executable_semantics/testdata/tuple5.carbon:8: Tuple field name 'y' does not match pattern field name 'x' EXIT CODE: 255 diff --git a/executable_semantics/testdata/tuple_equality3.golden b/executable_semantics/testdata/tuple_equality3.golden index ff31cb848557..bd6c8490f6a5 100644 --- a/executable_semantics/testdata/tuple_equality3.golden +++ b/executable_semantics/testdata/tuple_equality3.golden @@ -1,4 +1,4 @@ -COMPILATION ERROR: 8: type error in == +COMPILATION ERROR: executable_semantics/testdata/tuple_equality3.carbon:8: type error in == expected: (0 = i32, 1 = i32) actual: (0 = i32) EXIT CODE: 255