diff --git a/toolchain/diagnostics/diagnostic_registry.def b/toolchain/diagnostics/diagnostic_registry.def index 14103ce4e379..3a209faacff9 100644 --- a/toolchain/diagnostics/diagnostic_registry.def +++ b/toolchain/diagnostics/diagnostic_registry.def @@ -78,6 +78,12 @@ CARBON_DIAGNOSTIC_KIND(ExpectedSemiToEndPackageDirective) // For-specific diagnostics CARBON_DIAGNOSTIC_KIND(ExpectedIn) +// ============================================================================ +// Semantics diagnostics +// ============================================================================ + +CARBON_DIAGNOSTIC_KIND(TypeMismatch) + // ============================================================================ // Other diagnostics // ============================================================================ diff --git a/toolchain/driver/driver.cpp b/toolchain/driver/driver.cpp index 68728a749083..dcfd9efe9d8a 100644 --- a/toolchain/driver/driver.cpp +++ b/toolchain/driver/driver.cpp @@ -175,7 +175,7 @@ auto Driver::RunDumpSubcommand(DiagnosticConsumer& consumer, const SemanticsIR builtin_ir = SemanticsIR::MakeBuiltinIR(); const SemanticsIR semantics_ir = SemanticsIR::MakeFromParseTree( - builtin_ir, tokenized_source, parse_tree, vlog_stream_); + builtin_ir, tokenized_source, parse_tree, consumer, vlog_stream_); if (dump_mode == DumpMode::SemanticsIR) { consumer.Flush(); semantics_ir.Print(output_stream_); diff --git a/toolchain/lexer/numeric_literal.h b/toolchain/lexer/numeric_literal.h index 52fb693b86d5..e34f81a9d664 100644 --- a/toolchain/lexer/numeric_literal.h +++ b/toolchain/lexer/numeric_literal.h @@ -32,7 +32,7 @@ class LexedNumericLiteral { Radix radix; // The mantissa, represented as a variable-width unsigned integer. llvm::APInt mantissa; - // The exponent, represented as a variable-width signed integer.. + // The exponent, represented as a variable-width signed integer. llvm::APInt exponent; }; diff --git a/toolchain/lexer/tokenized_buffer.cpp b/toolchain/lexer/tokenized_buffer.cpp index 876bd8187108..582a416e7ba5 100644 --- a/toolchain/lexer/tokenized_buffer.cpp +++ b/toolchain/lexer/tokenized_buffer.cpp @@ -85,9 +85,9 @@ class TokenizedBuffer::Lexer { Lexer(TokenizedBuffer& buffer, DiagnosticConsumer& consumer) : buffer_(&buffer), - translator_(buffer, ¤t_column_), + translator_(&buffer, ¤t_column_), emitter_(translator_, consumer), - token_translator_(buffer, ¤t_column_), + token_translator_(&buffer, ¤t_column_), token_emitter_(token_translator_, consumer), current_line_(buffer.AddLine({0, 0, 0})), current_line_info_(&buffer.GetLineInfo(current_line_)) {} @@ -944,7 +944,7 @@ auto TokenizedBuffer::TokenLocationTranslator::GetLocation(Token token) // Find the corresponding file location. // TODO: Should we somehow indicate in the diagnostic location if this token // is a recovery token that doesn't correspond to the original source? - return SourceBufferLocationTranslator(*buffer_, last_line_lexed_to_column_) + return SourceBufferLocationTranslator(buffer_, last_line_lexed_to_column_) .GetLocation(token_start); } diff --git a/toolchain/lexer/tokenized_buffer.h b/toolchain/lexer/tokenized_buffer.h index 70164535af51..4b1968517d81 100644 --- a/toolchain/lexer/tokenized_buffer.h +++ b/toolchain/lexer/tokenized_buffer.h @@ -253,16 +253,16 @@ class TokenizedBuffer { class TokenLocationTranslator : public DiagnosticLocationTranslator { public: - explicit TokenLocationTranslator(TokenizedBuffer& buffer, + explicit TokenLocationTranslator(const TokenizedBuffer* buffer, int* last_line_lexed_to_column) - : buffer_(&buffer), + : buffer_(buffer), last_line_lexed_to_column_(last_line_lexed_to_column) {} // Map the given token into a diagnostic location. auto GetLocation(Token token) -> DiagnosticLocation override; private: - TokenizedBuffer* buffer_; + const TokenizedBuffer* buffer_; // Passed to SourceBufferLocationTranslator. int* last_line_lexed_to_column_; }; @@ -377,9 +377,9 @@ class TokenizedBuffer { class SourceBufferLocationTranslator : public DiagnosticLocationTranslator { public: - explicit SourceBufferLocationTranslator(TokenizedBuffer& buffer, + explicit SourceBufferLocationTranslator(const TokenizedBuffer* buffer, int* last_line_lexed_to_column) - : buffer_(&buffer), + : buffer_(buffer), last_line_lexed_to_column_(last_line_lexed_to_column) {} // Map the given position within the source buffer into a diagnostic @@ -387,7 +387,7 @@ class TokenizedBuffer { auto GetLocation(const char* loc) -> DiagnosticLocation override; private: - TokenizedBuffer* buffer_; + const TokenizedBuffer* buffer_; // The last lexed column, for determining whether the last line should be // checked for unlexed newlines. May be null after lexing is complete. int* last_line_lexed_to_column_; diff --git a/toolchain/parser/parse_tree.cpp b/toolchain/parser/parse_tree.cpp index 83067011bf7c..a0f7bf48f07a 100644 --- a/toolchain/parser/parse_tree.cpp +++ b/toolchain/parser/parse_tree.cpp @@ -23,7 +23,7 @@ namespace Carbon { auto ParseTree::Parse(TokenizedBuffer& tokens, DiagnosticConsumer& consumer) -> ParseTree { TokenizedBuffer::TokenLocationTranslator translator( - tokens, /*last_line_lexed_to_column=*/nullptr); + &tokens, /*last_line_lexed_to_column=*/nullptr); TokenDiagnosticEmitter emitter(translator, consumer); // Delegate to the parser. diff --git a/toolchain/semantics/BUILD b/toolchain/semantics/BUILD index d6934b9b72a8..28f1fcfd48e6 100644 --- a/toolchain/semantics/BUILD +++ b/toolchain/semantics/BUILD @@ -44,6 +44,7 @@ cc_library( "//common:check", "//common:ostream", "//common:vlog", + "//toolchain/lexer:numeric_literal", "//toolchain/lexer:token_kind", "//toolchain/lexer:tokenized_buffer", "//toolchain/parser:parse_node_kind", diff --git a/toolchain/semantics/lit_autoupdate.py b/toolchain/semantics/lit_autoupdate.py index 51bd4078a745..3f18f6bf449b 100755 --- a/toolchain/semantics/lit_autoupdate.py +++ b/toolchain/semantics/lit_autoupdate.py @@ -26,9 +26,7 @@ def main() -> None: "--tool=carbon", "--autoupdate_arg=dump", "--autoupdate_arg=semantics-ir", - # TODO: This should eventually have lines in output, but it doesn't - # right now. - "--line_number_pattern=UNUSED", + r"--line_number_pattern=(?<=\.carbon:)(\d+)(?=(?:\D|$))", "--lit_run=%{carbon-run-semantics}", "--testdata=toolchain/semantics/testdata", ] + sys.argv[1:] diff --git a/toolchain/semantics/semantics_builtin_kind.def b/toolchain/semantics/semantics_builtin_kind.def index 7db2db32c579..b5b1402ba8c1 100644 --- a/toolchain/semantics/semantics_builtin_kind.def +++ b/toolchain/semantics/semantics_builtin_kind.def @@ -13,9 +13,19 @@ #error "Must define the x-macro to use this file." #endif +// Tracks expressions which are valid as types. CARBON_SEMANTICS_BUILTIN_KIND(TypeType) + +// Used when a SemanticNode has an invalid type, which should then be ignored +// for future type checking. +CARBON_SEMANTICS_BUILTIN_KIND(InvalidType) + +// The type of an integer literal. CARBON_SEMANTICS_BUILTIN_KIND(IntegerLiteralType) +// The type of a real literal. +CARBON_SEMANTICS_BUILTIN_KIND(RealLiteralType) + // Keep invalid last, so that we can use values as array indices without needing // an invalid entry. CARBON_SEMANTICS_BUILTIN_KIND(Invalid) diff --git a/toolchain/semantics/semantics_ir.cpp b/toolchain/semantics/semantics_ir.cpp index b70db517b6ee..369c3768b5ca 100644 --- a/toolchain/semantics/semantics_ir.cpp +++ b/toolchain/semantics/semantics_ir.cpp @@ -20,23 +20,36 @@ auto SemanticsIR::MakeBuiltinIR() -> SemanticsIR { semantics.cross_references_.resize_for_overwrite( SemanticsBuiltinKind::ValidCount); - // TODO: The type-type should be replaced with a constraint. It will probably - // remain a builtin, just reimplemented as equivalent to `constraint type {}`. - auto builtin_type_type = semantics.AddNode( + constexpr int32_t TypeOfTypeType = 0; + auto type_type = semantics.AddNode( block_id, SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::TypeType(), - SemanticsNodeId(0))); + SemanticsNodeId(TypeOfTypeType))); semantics.cross_references_[SemanticsBuiltinKind::TypeType().AsInt()] = - SemanticsCrossReference(BuiltinIR, block_id, builtin_type_type); - CARBON_CHECK(builtin_type_type.id == 0) + SemanticsCrossReference(BuiltinIR, block_id, type_type); + CARBON_CHECK(type_type.id == TypeOfTypeType) << "TypeType's type must be self-referential."; - auto builtin_int32 = semantics.AddNode( - block_id, - SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::IntegerLiteralType(), - builtin_type_type)); + constexpr int32_t TypeOfInvalidType = 1; + auto invalid_type = semantics.AddNode( + block_id, SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::InvalidType(), + SemanticsNodeId(TypeOfInvalidType))); + semantics.cross_references_[SemanticsBuiltinKind::InvalidType().AsInt()] = + SemanticsCrossReference(BuiltinIR, block_id, invalid_type); + CARBON_CHECK(invalid_type.id == TypeOfInvalidType) + << "InvalidType's type must be self-referential."; + + auto integer_literal_type = semantics.AddNode( + block_id, SemanticsNode::MakeBuiltin( + SemanticsBuiltinKind::IntegerLiteralType(), type_type)); semantics .cross_references_[SemanticsBuiltinKind::IntegerLiteralType().AsInt()] = - SemanticsCrossReference(BuiltinIR, block_id, builtin_int32); + SemanticsCrossReference(BuiltinIR, block_id, integer_literal_type); + + auto real_literal_type = semantics.AddNode( + block_id, SemanticsNode::MakeBuiltin( + SemanticsBuiltinKind::RealLiteralType(), type_type)); + semantics.cross_references_[SemanticsBuiltinKind::RealLiteralType().AsInt()] = + SemanticsCrossReference(BuiltinIR, block_id, real_literal_type); CARBON_CHECK(semantics.node_blocks_.size() == 1) << "BuildBuiltins should only produce 1 block, actual: " @@ -47,10 +60,16 @@ auto SemanticsIR::MakeBuiltinIR() -> SemanticsIR { auto SemanticsIR::MakeFromParseTree(const SemanticsIR& builtin_ir, const TokenizedBuffer& tokens, const ParseTree& parse_tree, + DiagnosticConsumer& consumer, llvm::raw_ostream* vlog_stream) -> SemanticsIR { SemanticsIR semantics(builtin_ir); - SemanticsParseTreeHandler(tokens, parse_tree, semantics, vlog_stream).Build(); + + TokenizedBuffer::TokenLocationTranslator translator( + &tokens, /*last_line_lexed_to_column=*/nullptr); + TokenDiagnosticEmitter emitter(translator, consumer); + SemanticsParseTreeHandler(tokens, emitter, parse_tree, semantics, vlog_stream) + .Build(); return semantics; } @@ -62,8 +81,8 @@ auto SemanticsIR::Print(llvm::raw_ostream& out) const -> void { out << "cross_references = {\n"; for (int32_t i = 0; i < static_cast(cross_references_.size()); ++i) { out.indent(Indent); - out << SemanticsNodeId::MakeCrossReference(i) << " = \"" - << cross_references_[i] << "\";\n"; + out << SemanticsNodeId::MakeCrossReference(i) << " = " + << cross_references_[i] << ";\n"; } out << "},\n"; diff --git a/toolchain/semantics/semantics_ir.h b/toolchain/semantics/semantics_ir.h index 3ce1fce388d3..86276577a48f 100644 --- a/toolchain/semantics/semantics_ir.h +++ b/toolchain/semantics/semantics_ir.h @@ -7,6 +7,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +#include "toolchain/lexer/numeric_literal.h" #include "toolchain/parser/parse_tree.h" #include "toolchain/semantics/semantics_node.h" @@ -21,6 +22,15 @@ struct SemanticsCrossReferenceIRId { SemanticsCrossReferenceIRId() : id(-1) {} constexpr explicit SemanticsCrossReferenceIRId(int32_t id) : id(id) {} + friend auto operator==(SemanticsCrossReferenceIRId lhs, + SemanticsCrossReferenceIRId rhs) -> bool { + return lhs.id == rhs.id; + } + friend auto operator!=(SemanticsCrossReferenceIRId lhs, + SemanticsCrossReferenceIRId rhs) -> bool { + return lhs.id != rhs.id; + } + auto Print(llvm::raw_ostream& out) const -> void { out << "ir" << id; } int32_t id; @@ -53,6 +63,7 @@ class SemanticsIR { static auto MakeFromParseTree(const SemanticsIR& builtin_ir, const TokenizedBuffer& tokens, const ParseTree& parse_tree, + DiagnosticConsumer& consumer, llvm::raw_ostream* vlog_stream) -> SemanticsIR; // Prints the full IR. @@ -61,6 +72,10 @@ class SemanticsIR { private: friend class SemanticsParseTreeHandler; + // As noted under cross_reference_irs_, the current IR must always be at + // index 1. This is a constant for that. + static constexpr auto ThisIR = SemanticsCrossReferenceIRId(1); + // For the builtin IR only. SemanticsIR() : SemanticsIR(*this) {} // For most IRs. @@ -68,6 +83,30 @@ class SemanticsIR { : cross_reference_irs_({&builtins, this}), cross_references_(builtins.cross_references_) {} + auto GetType(SemanticsNodeBlockId block_id, SemanticsNodeId node_id) + -> SemanticsNodeId { + if (node_id.is_cross_reference()) { + auto ref = cross_references_[node_id.GetAsCrossReference()]; + auto type = cross_reference_irs_[ref.ir.id] + ->node_blocks_[ref.node_block.id][ref.node.id] + .type(); + if (type.is_cross_reference() || + (ref.ir == ThisIR && ref.node_block == block_id)) { + return type; + } else { + // TODO: If the type is a local reference within a block other than the + // present one, we don't really want to add a cross reference at this + // point. Does this mean types should be required to be cross + // references? And maybe always with a presence in the current IR's + // cross-references, so that equality is straightforward even though + // resolving the actual type is a two-step process? + CARBON_FATAL() << "Need to think more about this case"; + } + } else { + return node_blocks_[block_id.id][node_id.id].type(); + } + } + // Adds an identifier, returning an ID to reference it. // TODO: Deduplicate strings. // TODO: Probably make generic for all strings, including literals. diff --git a/toolchain/semantics/semantics_node.h b/toolchain/semantics/semantics_node.h index 222ae2777637..677aeb520f8c 100644 --- a/toolchain/semantics/semantics_node.h +++ b/toolchain/semantics/semantics_node.h @@ -42,6 +42,13 @@ struct SemanticsNodeId { return id & ~CrossReferenceBit; } + friend auto operator==(SemanticsNodeId lhs, SemanticsNodeId rhs) -> bool { + return lhs.id == rhs.id; + } + friend auto operator!=(SemanticsNodeId lhs, SemanticsNodeId rhs) -> bool { + return lhs.id != rhs.id; + } + auto Print(llvm::raw_ostream& out) const -> void { if (is_cross_reference()) { out << "node_xref" << GetAsCrossReference(); @@ -58,6 +65,15 @@ struct SemanticsIdentifierId { SemanticsIdentifierId() : id(-1) {} explicit SemanticsIdentifierId(int32_t id) : id(id) {} + friend auto operator==(SemanticsIdentifierId lhs, SemanticsIdentifierId rhs) + -> bool { + return lhs.id == rhs.id; + } + friend auto operator!=(SemanticsIdentifierId lhs, SemanticsIdentifierId rhs) + -> bool { + return lhs.id != rhs.id; + } + auto Print(llvm::raw_ostream& out) const -> void { out << "ident" << id; } int32_t id; @@ -68,6 +84,15 @@ struct SemanticsIntegerLiteralId { SemanticsIntegerLiteralId() : id(-1) {} explicit SemanticsIntegerLiteralId(int32_t id) : id(id) {} + friend auto operator==(SemanticsIntegerLiteralId lhs, + SemanticsIntegerLiteralId rhs) -> bool { + return lhs.id == rhs.id; + } + friend auto operator!=(SemanticsIntegerLiteralId lhs, + SemanticsIntegerLiteralId rhs) -> bool { + return lhs.id != rhs.id; + } + auto Print(llvm::raw_ostream& out) const -> void { out << "int" << id; } int32_t id; @@ -78,6 +103,15 @@ struct SemanticsNodeBlockId { SemanticsNodeBlockId() : id(-1) {} explicit SemanticsNodeBlockId(int32_t id) : id(id) {} + friend auto operator==(SemanticsNodeBlockId lhs, SemanticsNodeBlockId rhs) + -> bool { + return lhs.id == rhs.id; + } + friend auto operator!=(SemanticsNodeBlockId lhs, SemanticsNodeBlockId rhs) + -> bool { + return lhs.id != rhs.id; + } + auto Print(llvm::raw_ostream& out) const -> void { out << "block" << id; } int32_t id; @@ -91,10 +125,10 @@ class SemanticsNode { auto GetAsInvalid() const -> NoArgs { CARBON_FATAL() << "Invalid access"; } static auto MakeBinaryOperatorAdd(ParseTree::Node parse_node, - SemanticsNodeId lhs, SemanticsNodeId rhs) - -> SemanticsNode { + SemanticsNodeId type, SemanticsNodeId lhs, + SemanticsNodeId rhs) -> SemanticsNode { return SemanticsNode(parse_node, SemanticsNodeKind::BinaryOperatorAdd(), - SemanticsNodeId(), lhs.id, rhs.id); + type, lhs.id, rhs.id); } auto GetAsBinaryOperatorAdd() const -> std::pair { @@ -173,7 +207,20 @@ class SemanticsNode { return SemanticsIntegerLiteralId(arg0_); } + static auto MakeRealLiteral(ParseTree::Node parse_node) -> SemanticsNode { + return SemanticsNode(parse_node, SemanticsNodeKind::RealLiteral(), + SemanticsNodeId::MakeBuiltinReference( + SemanticsBuiltinKind::RealLiteralType())); + } + auto GetAsRealLiteral() const -> NoArgs { + CARBON_CHECK(kind_ == SemanticsNodeKind::RealLiteral()); + return {}; + } + static auto MakeReturn(ParseTree::Node parse_node) -> SemanticsNode { + // The actual type is `()`. However, code dealing with `return;` should + // understand the type without checking, so it's not necessary but could be + // specified if needed. return SemanticsNode(parse_node, SemanticsNodeKind::Return(), SemanticsNodeId()); } @@ -183,9 +230,10 @@ class SemanticsNode { } static auto MakeReturnExpression(ParseTree::Node parse_node, - SemanticsNodeId expr) -> SemanticsNode { + SemanticsNodeId type, SemanticsNodeId expr) + -> SemanticsNode { return SemanticsNode(parse_node, SemanticsNodeKind::ReturnExpression(), - SemanticsNodeId(), expr.id); + type, expr.id); } auto GetAsReturnExpression() const -> SemanticsNodeId { CARBON_CHECK(kind_ == SemanticsNodeKind::ReturnExpression()); diff --git a/toolchain/semantics/semantics_node_kind.def b/toolchain/semantics/semantics_node_kind.def index 896b9762799c..86a37b969b3e 100644 --- a/toolchain/semantics/semantics_node_kind.def +++ b/toolchain/semantics/semantics_node_kind.def @@ -22,6 +22,7 @@ CARBON_SEMANTICS_NODE_KIND(CodeBlock) CARBON_SEMANTICS_NODE_KIND(FunctionDeclaration) CARBON_SEMANTICS_NODE_KIND(FunctionDefinition) CARBON_SEMANTICS_NODE_KIND(IntegerLiteral) +CARBON_SEMANTICS_NODE_KIND(RealLiteral) CARBON_SEMANTICS_NODE_KIND(Return) CARBON_SEMANTICS_NODE_KIND(ReturnExpression) diff --git a/toolchain/semantics/semantics_parse_tree_handler.cpp b/toolchain/semantics/semantics_parse_tree_handler.cpp index a380d8fac4ce..e5afb79f1afa 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.cpp +++ b/toolchain/semantics/semantics_parse_tree_handler.cpp @@ -9,6 +9,7 @@ #include "toolchain/lexer/token_kind.h" #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/parser/parse_node_kind.h" +#include "toolchain/semantics/semantics_builtin_kind.h" #include "toolchain/semantics/semantics_node.h" namespace Carbon { @@ -219,12 +220,29 @@ auto SemanticsParseTreeHandler::HandleInfixOperator(ParseTree::Node parse_node) auto rhs_id = PopWithResult(); auto lhs_id = PopWithResult(); + auto block = node_block_stack_.back(); + auto lhs_type = semantics_->GetType(block, lhs_id); + auto rhs_type = semantics_->GetType(block, rhs_id); + SemanticsNodeId result_type = lhs_type; + // TODO: This should attempt a type conversion, but there's not enough + // implemented to do that right now. + if (lhs_type != rhs_type) { + auto invalid_type = SemanticsNodeId::MakeBuiltinReference( + SemanticsBuiltinKind::InvalidType()); + if (lhs_type != invalid_type && rhs_type != invalid_type) { + // TODO: This is a poor diagnostic, and should be expanded. + CARBON_DIAGNOSTIC(TypeMismatch, Error, "Type mismatch"); + emitter_->Emit(parse_tree_->node_token(parse_node), TypeMismatch); + } + result_type = invalid_type; + } + // Figure out the operator for the token. auto token = parse_tree_->node_token(parse_node); switch (auto token_kind = tokens_->GetKind(token)) { case TokenKind::Plus(): - Push(parse_node, - SemanticsNode::MakeBinaryOperatorAdd(parse_node, lhs_id, rhs_id)); + Push(parse_node, SemanticsNode::MakeBinaryOperatorAdd( + parse_node, result_type, lhs_id, rhs_id)); break; default: CARBON_FATAL() << "Unrecognized token kind: " << token_kind.Name(); @@ -241,6 +259,11 @@ auto SemanticsParseTreeHandler::HandleLiteral(ParseTree::Node parse_node) Push(parse_node, SemanticsNode::MakeIntegerLiteral(parse_node, id)); break; } + case TokenKind::RealLiteral(): { + // TODO: Add storage of the Real literal. + Push(parse_node, SemanticsNode::MakeRealLiteral(parse_node)); + break; + } default: CARBON_FATAL() << "Unhandled kind: " << token_kind.Name(); } @@ -264,8 +287,10 @@ auto SemanticsParseTreeHandler::HandleReturnStatement( Push(parse_node, SemanticsNode::MakeReturn(parse_node)); } else { auto arg = PopWithResult(); + auto arg_type = semantics_->GetType(node_block_stack_.back(), arg); Pop(ParseNodeKind::ReturnStatementStart()); - Push(parse_node, SemanticsNode::MakeReturnExpression(parse_node, arg)); + Push(parse_node, + SemanticsNode::MakeReturnExpression(parse_node, arg_type, arg)); } } diff --git a/toolchain/semantics/semantics_parse_tree_handler.h b/toolchain/semantics/semantics_parse_tree_handler.h index 74a85f02f582..b49083bfeaa7 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.h +++ b/toolchain/semantics/semantics_parse_tree_handler.h @@ -16,10 +16,12 @@ class SemanticsParseTreeHandler { public: // Stores references for work. explicit SemanticsParseTreeHandler(const TokenizedBuffer& tokens, + TokenDiagnosticEmitter& emitter, const ParseTree& parse_tree, SemanticsIR& semantics, llvm::raw_ostream* vlog_stream) : tokens_(&tokens), + emitter_(&emitter), parse_tree_(&parse_tree), semantics_(&semantics), vlog_stream_(vlog_stream) {} @@ -75,6 +77,9 @@ class SemanticsParseTreeHandler { // Tokens for getting data on literals. const TokenizedBuffer* tokens_; + // Handles diagnostics. + TokenDiagnosticEmitter* emitter_; + // The file's parse tree. const ParseTree* parse_tree_; diff --git a/toolchain/semantics/testdata/basics/empty.carbon b/toolchain/semantics/testdata/basics/empty.carbon index aed964adfc55..e70c818d0d85 100644 --- a/toolchain/semantics/testdata/basics/empty.carbon +++ b/toolchain/semantics/testdata/basics/empty.carbon @@ -6,8 +6,10 @@ // RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs.size == 2, // CHECK:STDOUT: cross_references = { -// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; -// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); // CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: }, diff --git a/toolchain/semantics/testdata/function/basic.carbon b/toolchain/semantics/testdata/function/basic.carbon index 6d7cd85795a6..b1dcca36db35 100644 --- a/toolchain/semantics/testdata/function/basic.carbon +++ b/toolchain/semantics/testdata/function/basic.carbon @@ -6,8 +6,10 @@ // RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs.size == 2, // CHECK:STDOUT: cross_references = { -// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; -// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); // CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Foo"; diff --git a/toolchain/semantics/testdata/function/order.carbon b/toolchain/semantics/testdata/function/order.carbon index 5dea70875fba..ea30f23a3384 100644 --- a/toolchain/semantics/testdata/function/order.carbon +++ b/toolchain/semantics/testdata/function/order.carbon @@ -6,8 +6,10 @@ // RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs.size == 2, // CHECK:STDOUT: cross_references = { -// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; -// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); // CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Foo"; diff --git a/toolchain/semantics/testdata/return/binary_op.carbon b/toolchain/semantics/testdata/operators/binary_op.carbon similarity index 64% rename from toolchain/semantics/testdata/return/binary_op.carbon rename to toolchain/semantics/testdata/operators/binary_op.carbon index ea93800e9ea4..3d23d5e1ac93 100644 --- a/toolchain/semantics/testdata/return/binary_op.carbon +++ b/toolchain/semantics/testdata/operators/binary_op.carbon @@ -6,8 +6,10 @@ // RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs.size == 2, // CHECK:STDOUT: cross_references = { -// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; -// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); // CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Main"; @@ -23,10 +25,10 @@ // CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); // CHECK:STDOUT: }, // CHECK:STDOUT: block1 = { -// CHECK:STDOUT: node0 = IntegerLiteral(int0): node_xref1; -// CHECK:STDOUT: node1 = IntegerLiteral(int1): node_xref1; -// CHECK:STDOUT: node2 = BinaryOperatorAdd(node0, node1); -// CHECK:STDOUT: node3 = ReturnExpression(node2); +// CHECK:STDOUT: node0 = IntegerLiteral(int0): node_xref2; +// CHECK:STDOUT: node1 = IntegerLiteral(int1): node_xref2; +// CHECK:STDOUT: node2 = BinaryOperatorAdd(node0, node1): node_xref2; +// CHECK:STDOUT: node3 = ReturnExpression(node2): node_xref2; // CHECK:STDOUT: }, // CHECK:STDOUT: } diff --git a/toolchain/semantics/testdata/operators/type_mismatch.carbon b/toolchain/semantics/testdata/operators/type_mismatch.carbon new file mode 100644 index 000000000000..95290b1cbd28 --- /dev/null +++ b/toolchain/semantics/testdata/operators/type_mismatch.carbon @@ -0,0 +1,37 @@ +// 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 +// +// AUTOUPDATE +// RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); +// CHECK:STDOUT: }, +// CHECK:STDOUT: identifiers = { +// CHECK:STDOUT: ident0 = "Main"; +// CHECK:STDOUT: }, +// CHECK:STDOUT: integer_literals = { +// CHECK:STDOUT: int0 = 12; +// CHECK:STDOUT: }, +// CHECK:STDOUT: node_blocks = { +// CHECK:STDOUT: block0 = { +// CHECK:STDOUT: node0 = FunctionDeclaration(); +// CHECK:STDOUT: node1 = BindName(ident0, node0); +// CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); +// CHECK:STDOUT: }, +// CHECK:STDOUT: block1 = { +// CHECK:STDOUT: node0 = IntegerLiteral(int0): node_xref2; +// CHECK:STDOUT: node1 = RealLiteral(): node_xref3; +// CHECK:STDOUT: node2 = BinaryOperatorAdd(node0, node1): node_xref1; +// CHECK:STDOUT: node3 = ReturnExpression(node2): node_xref1; +// CHECK:STDOUT: }, +// CHECK:STDOUT: } + +fn Main() { + // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/type_mismatch.carbon:[[@LINE+1]]:13: Type mismatch + return 12 + 3.4; +} diff --git a/toolchain/semantics/testdata/operators/type_mismatch_once.carbon b/toolchain/semantics/testdata/operators/type_mismatch_once.carbon new file mode 100644 index 000000000000..e5b33f93b6b3 --- /dev/null +++ b/toolchain/semantics/testdata/operators/type_mismatch_once.carbon @@ -0,0 +1,42 @@ +// 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 +// +// AUTOUPDATE +// RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); +// CHECK:STDOUT: }, +// CHECK:STDOUT: identifiers = { +// CHECK:STDOUT: ident0 = "Main"; +// CHECK:STDOUT: }, +// CHECK:STDOUT: integer_literals = { +// CHECK:STDOUT: int0 = 12; +// CHECK:STDOUT: int1 = 12; +// CHECK:STDOUT: }, +// CHECK:STDOUT: node_blocks = { +// CHECK:STDOUT: block0 = { +// CHECK:STDOUT: node0 = FunctionDeclaration(); +// CHECK:STDOUT: node1 = BindName(ident0, node0); +// CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); +// CHECK:STDOUT: }, +// CHECK:STDOUT: block1 = { +// CHECK:STDOUT: node0 = IntegerLiteral(int0): node_xref2; +// CHECK:STDOUT: node1 = RealLiteral(): node_xref3; +// CHECK:STDOUT: node2 = BinaryOperatorAdd(node0, node1): node_xref1; +// CHECK:STDOUT: node3 = IntegerLiteral(int1): node_xref2; +// CHECK:STDOUT: node4 = BinaryOperatorAdd(node2, node3): node_xref1; +// CHECK:STDOUT: node5 = ReturnExpression(node4): node_xref1; +// CHECK:STDOUT: }, +// CHECK:STDOUT: } + +fn Main() { + // The following line has two mismatches, but after the first, it shouldn't + // keep erroring. + // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/type_mismatch_once.carbon:[[@LINE+1]]:13: Type mismatch + return 12 + 3.4 + 12; +} diff --git a/toolchain/semantics/testdata/return/literal.carbon b/toolchain/semantics/testdata/return/literal.carbon index c2dac54a9978..fb88269c8f79 100644 --- a/toolchain/semantics/testdata/return/literal.carbon +++ b/toolchain/semantics/testdata/return/literal.carbon @@ -6,8 +6,10 @@ // RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs.size == 2, // CHECK:STDOUT: cross_references = { -// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; -// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); // CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Main"; @@ -22,8 +24,8 @@ // CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); // CHECK:STDOUT: }, // CHECK:STDOUT: block1 = { -// CHECK:STDOUT: node0 = IntegerLiteral(int0): node_xref1; -// CHECK:STDOUT: node1 = ReturnExpression(node0); +// CHECK:STDOUT: node0 = IntegerLiteral(int0): node_xref2; +// CHECK:STDOUT: node1 = ReturnExpression(node0): node_xref2; // CHECK:STDOUT: }, // CHECK:STDOUT: } diff --git a/toolchain/semantics/testdata/return/trivial.carbon b/toolchain/semantics/testdata/return/trivial.carbon index 0928a9360cf2..6f87dcc4dee7 100644 --- a/toolchain/semantics/testdata/return/trivial.carbon +++ b/toolchain/semantics/testdata/return/trivial.carbon @@ -6,8 +6,10 @@ // RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs.size == 2, // CHECK:STDOUT: cross_references = { -// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; -// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); // CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Main";