diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 97889bd1fe80..a3a2c3cad9e4 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -102,6 +102,7 @@ CARBON_DIAGNOSTIC_KIND(ReturnStatementDisallowExpression) CARBON_DIAGNOSTIC_KIND(ReturnStatementImplicitNote) CARBON_DIAGNOSTIC_KIND(ReturnStatementMissingExpression) CARBON_DIAGNOSTIC_KIND(ReturnStatementTypeMismatch) +CARBON_DIAGNOSTIC_KIND(ImplicitAsConversionFailure) // ============================================================================ // Other diagnostics diff --git a/toolchain/lowering/lowering.cpp b/toolchain/lowering/lowering.cpp index 1e3bd1689570..7803e379aeeb 100644 --- a/toolchain/lowering/lowering.cpp +++ b/toolchain/lowering/lowering.cpp @@ -176,6 +176,26 @@ auto Lowering::HandleStringLiteralNode(SemanticsNodeId /*node_id*/, CARBON_FATAL() << "TODO: Add support: " << node; } +auto Lowering::HandleStructTypeNode(SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto Lowering::HandleStructTypeFieldNode(SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto Lowering::HandleStructValueNode(SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto Lowering::HandleStubReferenceNode(SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + auto Lowering::HandleVarStorageNode(SemanticsNodeId /*node_id*/, SemanticsNode node) -> void { CARBON_FATAL() << "TODO: Add support: " << node; diff --git a/toolchain/semantics/semantics_builtin_kind.def b/toolchain/semantics/semantics_builtin_kind.def index 036f1c7c29fd..b4eafcaad79a 100644 --- a/toolchain/semantics/semantics_builtin_kind.def +++ b/toolchain/semantics/semantics_builtin_kind.def @@ -60,6 +60,12 @@ CARBON_SEMANTICS_BUILTIN_KIND(FloatingPointType, TypeType, "f64") // The type of string values and String literals. CARBON_SEMANTICS_BUILTIN_KIND(StringType, TypeType, "String") +// The canonical empty struct type. +CARBON_SEMANTICS_BUILTIN_KIND(EmptyStructType, TypeType, "{} as Type") + +// The canonical empty struct. +CARBON_SEMANTICS_BUILTIN_KIND(EmptyStruct, EmptyStructType, "{}") + // The canonical empty tuple type. CARBON_SEMANTICS_BUILTIN_KIND(EmptyTupleType, TypeType, "() as Type") diff --git a/toolchain/semantics/semantics_ir.cpp b/toolchain/semantics/semantics_ir.cpp index fa00d3401f7f..5649935e4cd4 100644 --- a/toolchain/semantics/semantics_ir.cpp +++ b/toolchain/semantics/semantics_ir.cpp @@ -128,6 +128,23 @@ auto SemanticsIR::StringifyNodeImpl(llvm::raw_ostream& out, auto node = GetNode(node_id); switch (node.kind()) { + case SemanticsNodeKind::StructType: { + out << "{"; + auto refs = GetNodeBlock(node.GetAsStructType().second); + llvm::ListSeparator sep; + for (const auto& ref_id : refs) { + out << sep; + // TODO: Bound recursion depth or remove recursive step. + StringifyNodeImpl(out, ref_id); + } + out << "}"; + break; + } + case SemanticsNodeKind::StructTypeField: { + out << "." << GetString(node.GetAsStructTypeField()) << ": "; + StringifyNodeImpl(out, node.type_id()); + break; + } case SemanticsNodeKind::Assign: case SemanticsNodeKind::BinaryOperatorAdd: case SemanticsNodeKind::BindName: @@ -142,6 +159,8 @@ auto SemanticsIR::StringifyNodeImpl(llvm::raw_ostream& out, case SemanticsNodeKind::Return: case SemanticsNodeKind::ReturnExpression: case SemanticsNodeKind::StringLiteral: + case SemanticsNodeKind::StructValue: + case SemanticsNodeKind::StubReference: case SemanticsNodeKind::VarStorage: // We don't need to handle stringification for nodes that don't show up in // errors, but make it clear what's going on so that it's clearer when diff --git a/toolchain/semantics/semantics_ir.h b/toolchain/semantics/semantics_ir.h index 70f0b617655b..780053a34b2b 100644 --- a/toolchain/semantics/semantics_ir.h +++ b/toolchain/semantics/semantics_ir.h @@ -106,6 +106,12 @@ class SemanticsIR { return node_blocks_[block_id.index]; } + // Returns the requested real literal. + auto GetRealLiteral(SemanticsRealLiteralId int_id) const + -> const SemanticsRealLiteral& { + return real_literals_[int_id.index]; + } + // Returns the requested string. auto GetString(SemanticsStringId string_id) const -> llvm::StringRef { return strings_[string_id.index]; diff --git a/toolchain/semantics/semantics_node.h b/toolchain/semantics/semantics_node.h index 70cdfe8dd6cb..504c51b8eda6 100644 --- a/toolchain/semantics/semantics_node.h +++ b/toolchain/semantics/semantics_node.h @@ -299,6 +299,20 @@ class SemanticsNode { SemanticsBuiltinKind::StringType.AsInt(), SemanticsStringId /*string_id*/>; + using StructType = FactoryPreTyped< + SemanticsNodeKind::StructType, SemanticsBuiltinKind::TypeType.AsInt(), + SemanticsNodeBlockId /*ir_id*/, SemanticsNodeBlockId /*refs_id*/>; + + using StructTypeField = Factory; + + using StructValue = + Factory; + + using StubReference = + Factory; + using VarStorage = Factory; SemanticsNode() diff --git a/toolchain/semantics/semantics_node_kind.def b/toolchain/semantics/semantics_node_kind.def index 417c199b4003..d9cac417859f 100644 --- a/toolchain/semantics/semantics_node_kind.def +++ b/toolchain/semantics/semantics_node_kind.def @@ -33,6 +33,10 @@ CARBON_SEMANTICS_NODE_KIND(RealLiteral) CARBON_SEMANTICS_NODE_KIND(Return) CARBON_SEMANTICS_NODE_KIND(ReturnExpression) CARBON_SEMANTICS_NODE_KIND(StringLiteral) +CARBON_SEMANTICS_NODE_KIND(StructType) +CARBON_SEMANTICS_NODE_KIND(StructTypeField) +CARBON_SEMANTICS_NODE_KIND(StructValue) +CARBON_SEMANTICS_NODE_KIND(StubReference) CARBON_SEMANTICS_NODE_KIND(VarStorage) #undef CARBON_SEMANTICS_NODE_KIND diff --git a/toolchain/semantics/semantics_node_stack.cpp b/toolchain/semantics/semantics_node_stack.cpp index 9a3650e7e86e..c3f4bbc19e63 100644 --- a/toolchain/semantics/semantics_node_stack.cpp +++ b/toolchain/semantics/semantics_node_stack.cpp @@ -130,16 +130,17 @@ auto SemanticsNodeStack::PopForParseNodeAndNodeId(ParseNodeKind pop_parse_kind) return {back.parse_node, back.node_id}; } -auto SemanticsNodeStack::PopForParseNodeAndNameId() +auto SemanticsNodeStack::PopForParseNodeAndNameId(ParseNodeKind pop_parse_kind) -> std::pair { - auto back = PopEntry(ParseNodeKind::PatternBinding); + auto back = PopEntry(pop_parse_kind); RequireValidId(back); return {back.parse_node, back.name_id}; } -auto SemanticsNodeStack::PeekForNameId() -> SemanticsStringId { +auto SemanticsNodeStack::PeekForNameId(ParseNodeKind parse_kind) + -> SemanticsStringId { auto back = stack_.back(); - RequireParseKind(back, ParseNodeKind::PatternBinding); + RequireParseKind(back, parse_kind); RequireValidId(back); return back.name_id; } diff --git a/toolchain/semantics/semantics_node_stack.h b/toolchain/semantics/semantics_node_stack.h index 5f9ff0a7f93c..1b22eeaf131d 100644 --- a/toolchain/semantics/semantics_node_stack.h +++ b/toolchain/semantics/semantics_node_stack.h @@ -45,10 +45,8 @@ class SemanticsNodeStack { PushEntry({.parse_node = parse_node, .node_id = node_id}, DebugLog::NodeId); } - // Pushes a PatternBinding parse tree node onto the stack with its name. + // Pushes a parse tree node onto the stack with its name. auto Push(ParseTree::Node parse_node, SemanticsStringId name_id) -> void { - CARBON_CHECK(parse_tree_->node_kind(parse_node) == - ParseNodeKind::PatternBinding); PushEntry({.parse_node = parse_node, .name_id = name_id}, DebugLog::NameId); } @@ -85,16 +83,14 @@ class SemanticsNodeStack { auto PopForNodeId() -> SemanticsNodeId; // Pops the top of the stack and returns the parse_node and name_id. - // Verifies that the parse_node is a PatternBinding. - auto PopForParseNodeAndNameId() + auto PopForParseNodeAndNameId(ParseNodeKind pop_parse_kind) -> std::pair; // Peeks at the parse_node of the top of the stack. auto PeekParseNode() -> ParseTree::Node { return stack_.back().parse_node; } // Peeks at the name_id of the top of the stack. - // Verifies that the parse_node is a PatternBinding. - auto PeekForNameId() -> SemanticsStringId; + auto PeekForNameId(ParseNodeKind parse_kind) -> SemanticsStringId; // Prints the stack for a stack dump. auto PrintForStackDump(llvm::raw_ostream& output) const -> void; @@ -115,8 +111,6 @@ class SemanticsNodeStack { // is used based on the ParseNodeKind. union { SemanticsNodeId node_id; - - // Right now name_id is exclusively for PatternBinding, which is enforced. SemanticsStringId name_id; }; }; diff --git a/toolchain/semantics/semantics_parse_tree_handler.cpp b/toolchain/semantics/semantics_parse_tree_handler.cpp index 26e0d90c51bf..1d94d1348b24 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.cpp +++ b/toolchain/semantics/semantics_parse_tree_handler.cpp @@ -232,68 +232,123 @@ auto SemanticsParseTreeHandler::TryTypeConversionOnArgs( return true; } +auto SemanticsParseTreeHandler::ImplicitAs(ParseTree::Node parse_node, + SemanticsNodeId value_id, + SemanticsNodeId as_type_id) + -> SemanticsNodeId { + // Start by making sure both sides are valid. If any part is invalid, the + // result is invalid and we shouldn't error. + if (value_id == SemanticsNodeId::BuiltinInvalidType || + as_type_id == SemanticsNodeId::BuiltinInvalidType) { + return SemanticsNodeId::BuiltinInvalidType; + } + auto value_type_id = semantics_->GetType(value_id); + if (value_type_id == SemanticsNodeId::BuiltinInvalidType) { + return SemanticsNodeId::BuiltinInvalidType; + } + + // If the type doesn't need to change, we can return the value directly. + if (value_type_id == as_type_id) { + return value_id; + } + + // When converting to a Type, there are some automatic conversions that can be + // done. + if (as_type_id == SemanticsNodeId::BuiltinTypeType) { + if (value_id == SemanticsNodeId::BuiltinEmptyTuple) { + return SemanticsNodeId::BuiltinEmptyTupleType; + } + if (value_id == SemanticsNodeId::BuiltinEmptyStruct) { + return SemanticsNodeId::BuiltinEmptyStructType; + } + } + + auto value_type = semantics_->GetNode(value_type_id); + auto as_type = semantics_->GetNode(as_type_id); + if (CanImplicitAsStruct(value_type, as_type)) { + return value_id; + } + + CARBON_DIAGNOSTIC(ImplicitAsConversionFailure, Error, + "Cannot implicitly convert from {0} to {1}.", std::string, + std::string); + emitter_ + ->Build(parse_node, ImplicitAsConversionFailure, + semantics_->StringifyNode(value_type_id), + semantics_->StringifyNode(as_type_id)) + .Emit(); + return SemanticsNodeId::BuiltinInvalidType; +} + +auto SemanticsParseTreeHandler::CanImplicitAsStruct(SemanticsNode value_type, + SemanticsNode as_type) + -> bool { + if (value_type.kind() != SemanticsNodeKind::StructType || + as_type.kind() != SemanticsNodeKind::StructType) { + return false; + } + auto value_type_refs = + semantics_->GetNodeBlock(value_type.GetAsStructType().second); + auto as_type_refs = + semantics_->GetNodeBlock(as_type.GetAsStructType().second); + if (value_type_refs.size() != as_type_refs.size()) { + return false; + } + + for (int i = 0; i < static_cast(value_type_refs.size()); ++i) { + auto value_type_field = semantics_->GetNode(value_type_refs[i]); + auto as_type_field = semantics_->GetNode(as_type_refs[i]); + if (value_type_field.type_id() != as_type_field.type_id() || + value_type_field.GetAsStructTypeField() != + as_type_field.GetAsStructTypeField()) { + return false; + } + } + return true; +} + auto SemanticsParseTreeHandler::ParamOrArgStart() -> void { params_or_args_stack_.Push(); node_block_stack_.Push(); } -auto SemanticsParseTreeHandler::ParamOrArgComma(ParseTree::Node parse_node) - -> bool { - node_stack_.Push(parse_node); - - // Copy the last node added to the IR block into the params block. - if (!ParamOrArgSave()) { - emitter_->Emit( - parse_node, SemanticsTodo, - "Should have a param before comma, will need error recovery"); - return false; - } - - return true; +auto SemanticsParseTreeHandler::ParamOrArgComma(bool for_args) -> void { + ParamOrArgSave(for_args); } -auto SemanticsParseTreeHandler::ParamOrArgEnd( - ParseNodeKind start_kind, ParseNodeKind comma_kind, - std::function on_start) - -> bool { - // If there's a node in the IR block that has yet to be added to the params - // block, add it now. - ParamOrArgSave(); - - while (true) { - auto parse_kind = parse_tree_->node_kind(node_stack_.PeekParseNode()); - if (parse_kind == start_kind) { - return on_start(node_block_stack_.Pop(), params_or_args_stack_.Pop()); - } else if (parse_kind == comma_kind) { - node_stack_.PopAndDiscardSoloParseNode(comma_kind); - } else { - node_stack_.PopAndIgnore(); - } +auto SemanticsParseTreeHandler::ParamOrArgEnd(bool for_args, + ParseNodeKind start_kind) + -> std::pair { + if (parse_tree_->node_kind(node_stack_.PeekParseNode()) != start_kind) { + ParamOrArgSave(for_args); } + return {node_block_stack_.Pop(), params_or_args_stack_.Pop()}; } -auto SemanticsParseTreeHandler::ParamOrArgSave() -> bool { - // Copy the last node added to the IR block into the params block. - auto ir_id = node_block_stack_.Peek(); - if (!ir_id.is_valid()) { - return false; +auto SemanticsParseTreeHandler::ParamOrArgSave(bool for_args) -> void { + SemanticsNodeId param_or_arg_id = SemanticsNodeId::Invalid; + if (for_args) { + // For an argument, we add a stub reference to the expression on the top of + // the stack. There may not be anything on the IR prior to this. + auto [entry_parse_node, entry_node_id] = + node_stack_.PopForParseNodeAndNodeId(); + param_or_arg_id = AddNode(SemanticsNode::StubReference::Make( + entry_parse_node, semantics_->GetNode(entry_node_id).type_id(), + entry_node_id)); + } else { + // For a parameter, there should always be something in the IR. + node_stack_.PopAndIgnore(); + auto ir_id = node_block_stack_.Peek(); + CARBON_CHECK(ir_id.is_valid()); + auto& ir = semantics_->GetNodeBlock(ir_id); + CARBON_CHECK(!ir.empty()) << "Should have had a param"; + param_or_arg_id = ir.back(); } - // We get params before ir because it may add a node block, which can - // invalidate the ir reference. - auto& params = semantics_->GetNodeBlock(params_or_args_stack_.PeekForAdd()); - - auto& ir = semantics_->GetNodeBlock(ir_id); - CARBON_CHECK(!ir.empty()) - << "Should only have a valid ID if a node was added"; - auto& param = ir.back(); - - if (!params.empty() && param == params.back()) { - // The param was already added after a comma. - return false; - } - params.push_back(ir.back()); - return true; + // Save the param or arg ID. + auto& params_or_args = + semantics_->GetNodeBlock(params_or_args_stack_.PeekForAdd()); + params_or_args.push_back(param_or_arg_id); } auto SemanticsParseTreeHandler::HandleAddress(ParseTree::Node parse_node) @@ -316,45 +371,44 @@ auto SemanticsParseTreeHandler::HandleBreakStatementStart( auto SemanticsParseTreeHandler::HandleCallExpression(ParseTree::Node parse_node) -> bool { - auto on_start = [&](SemanticsNodeBlockId ir_id, - SemanticsNodeBlockId refs_id) -> bool { - // TODO: Convert to call expression. - auto [call_expr_parse_node, name_id] = node_stack_.PopForParseNodeAndNodeId( - ParseNodeKind::CallExpressionStart); - auto name_node = semantics_->GetNode(name_id); - if (name_node.kind() != SemanticsNodeKind::FunctionDeclaration) { - // TODO: Work on error. - emitter_->Emit(parse_node, SemanticsTodo, "Not a callable name"); - node_stack_.Push(parse_node, name_id); - return true; - } + auto [ir_id, refs_id] = + ParamOrArgEnd(/*for_args=*/true, ParseNodeKind::CallExpressionStart); - auto [_, callable_id] = name_node.GetAsFunctionDeclaration(); - auto callable = semantics_->GetCallable(callable_id); - - if (!TryTypeConversionOnArgs(call_expr_parse_node, ir_id, refs_id, - name_node.parse_node(), - callable.param_refs_id)) { - node_stack_.Push(parse_node, SemanticsNodeId::BuiltinInvalidType); - return true; - } - - auto call_id = semantics_->AddCall({ir_id, refs_id}); - // TODO: Propagate return types from callable. - auto call_node_id = AddNode(SemanticsNode::Call::Make( - call_expr_parse_node, SemanticsNodeId::BuiltinEmptyTuple, call_id, - callable_id)); - - node_stack_.Push(parse_node, call_node_id); + // TODO: Convert to call expression. + auto [call_expr_parse_node, name_id] = + node_stack_.PopForParseNodeAndNodeId(ParseNodeKind::CallExpressionStart); + auto name_node = semantics_->GetNode(name_id); + if (name_node.kind() != SemanticsNodeKind::FunctionDeclaration) { + // TODO: Work on error. + emitter_->Emit(parse_node, SemanticsTodo, "Not a callable name"); + node_stack_.Push(parse_node, name_id); return true; - }; - return ParamOrArgEnd(ParseNodeKind::CallExpressionStart, - ParseNodeKind::CallExpressionComma, on_start); + } + + auto [_, callable_id] = name_node.GetAsFunctionDeclaration(); + auto callable = semantics_->GetCallable(callable_id); + + if (!TryTypeConversionOnArgs(call_expr_parse_node, ir_id, refs_id, + name_node.parse_node(), + callable.param_refs_id)) { + node_stack_.Push(parse_node, SemanticsNodeId::BuiltinInvalidType); + return true; + } + + auto call_id = semantics_->AddCall({ir_id, refs_id}); + // TODO: Propagate return types from callable. + auto call_node_id = AddNode(SemanticsNode::Call::Make( + call_expr_parse_node, SemanticsNodeId::BuiltinEmptyTuple, call_id, + callable_id)); + + node_stack_.Push(parse_node, call_node_id); + return true; } auto SemanticsParseTreeHandler::HandleCallExpressionComma( - ParseTree::Node parse_node) -> bool { - return ParamOrArgComma(parse_node); + ParseTree::Node /*parse_node*/) -> bool { + ParamOrArgComma(/*for_args=*/true); + return true; } auto SemanticsParseTreeHandler::HandleCallExpressionStart( @@ -434,8 +488,11 @@ auto SemanticsParseTreeHandler::HandleDeducedParameterListStart( auto SemanticsParseTreeHandler::HandleDesignatedName(ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleDesignatedName"); - return false; + auto name_str = parse_tree_->GetNodeText(parse_node); + auto name_id = semantics_->AddString(name_str); + // The parent is responsible for binding the name. + node_stack_.Push(parse_node, name_id); + return true; } auto SemanticsParseTreeHandler::HandleDesignatorExpression( @@ -782,21 +839,20 @@ auto SemanticsParseTreeHandler::HandlePackageLibrary(ParseTree::Node parse_node) auto SemanticsParseTreeHandler::HandleParameterList(ParseTree::Node parse_node) -> bool { - auto on_start = [&](SemanticsNodeBlockId ir_id, - SemanticsNodeBlockId refs_id) -> bool { - PopScope(); - node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::ParameterListStart); - finished_params_stack_.push_back({ir_id, refs_id}); - node_stack_.Push(parse_node); - return true; - }; - return ParamOrArgEnd(ParseNodeKind::ParameterListStart, - ParseNodeKind::ParameterListComma, on_start); + auto [ir_id, refs_id] = + ParamOrArgEnd(/*for_args=*/false, ParseNodeKind::ParameterListStart); + + PopScope(); + node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::ParameterListStart); + finished_params_stack_.push_back({ir_id, refs_id}); + node_stack_.Push(parse_node); + return true; } auto SemanticsParseTreeHandler::HandleParameterListComma( - ParseTree::Node parse_node) -> bool { - return ParamOrArgComma(parse_node); + ParseTree::Node /*parse_node*/) -> bool { + ParamOrArgComma(/*for_args=*/false); + return true; } auto SemanticsParseTreeHandler::HandleParameterListStart( @@ -822,16 +878,19 @@ auto SemanticsParseTreeHandler::HandleParenExpressionOrTupleLiteralStart( auto SemanticsParseTreeHandler::HandlePatternBinding(ParseTree::Node parse_node) -> bool { - auto type = node_stack_.PopForNodeId(); + auto [type_node, parsed_type] = node_stack_.PopForParseNodeAndNodeId(); + auto cast_type_id = + ImplicitAs(type_node, parsed_type, SemanticsNodeId::BuiltinTypeType); // Get the name. auto name_node = node_stack_.PopForSoloParseNode(); // Allocate storage, linked to the name for error locations. - auto storage_id = AddNode(SemanticsNode::VarStorage::Make(name_node, type)); + auto storage_id = + AddNode(SemanticsNode::VarStorage::Make(name_node, cast_type_id)); // Bind the name to storage. - auto name_id = BindName(name_node, type, storage_id); + auto name_id = BindName(name_node, cast_type_id, storage_id); // If this node's result is used, it'll be for either the name or the storage // address. The storage address can be found through the name, so we push the @@ -939,22 +998,35 @@ auto SemanticsParseTreeHandler::HandleSelfValueIdentifier( return false; } -auto SemanticsParseTreeHandler::HandleStructComma(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleStructComma"); - return false; +auto SemanticsParseTreeHandler::HandleStructComma( + ParseTree::Node /*parse_node*/) -> bool { + ParamOrArgComma( + /*for_args=*/parse_tree_->node_kind(node_stack_.PeekParseNode()) != + ParseNodeKind::StructFieldType); + return true; } auto SemanticsParseTreeHandler::HandleStructFieldDesignator( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleStructFieldDesignator"); - return false; + ParseTree::Node /*parse_node*/) -> bool { + // This leaves the designated name on top because the `.` isn't interesting. + CARBON_CHECK(parse_tree_->node_kind(node_stack_.PeekParseNode()) == + ParseNodeKind::DesignatedName); + return true; } auto SemanticsParseTreeHandler::HandleStructFieldType( ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleStructFieldType"); - return false; + auto [type_node, type_id] = node_stack_.PopForParseNodeAndNodeId(); + auto cast_type_id = + ImplicitAs(type_node, type_id, SemanticsNodeId::BuiltinTypeType); + + auto [name_node, name_id] = + node_stack_.PopForParseNodeAndNameId(ParseNodeKind::DesignatedName); + + AddNode( + SemanticsNode::StructTypeField::Make(name_node, cast_type_id, name_id)); + node_stack_.Push(parse_node); + return true; } auto SemanticsParseTreeHandler::HandleStructFieldUnknown( @@ -965,27 +1037,81 @@ auto SemanticsParseTreeHandler::HandleStructFieldUnknown( auto SemanticsParseTreeHandler::HandleStructFieldValue( ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleStructFieldValue"); - return false; + auto [value_parse_node, value_node_id] = + node_stack_.PopForParseNodeAndNodeId(); + auto [_, name_id] = + node_stack_.PopForParseNodeAndNameId(ParseNodeKind::DesignatedName); + + // Store the name for the type. + auto type_block_id = args_type_info_stack_.PeekForAdd(); + semantics_->AddNode( + type_block_id, + SemanticsNode::StructTypeField::Make( + parse_node, semantics_->GetNode(value_node_id).type_id(), name_id)); + + // Push the value back on the stack as an argument. + node_stack_.Push(parse_node, value_node_id); + return true; } auto SemanticsParseTreeHandler::HandleStructLiteral(ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleStructLiteral"); - return false; + auto [ir_id, refs_id] = ParamOrArgEnd( + /*for_args=*/true, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + + PopScope(); + node_stack_.PopAndDiscardSoloParseNode( + ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + auto type_block_id = args_type_info_stack_.Pop(); + + // Special-case `{}`. + if (refs_id == SemanticsNodeBlockId::Empty) { + node_stack_.Push(parse_node, SemanticsNodeId::BuiltinEmptyStruct); + return true; + } + + // Construct a type for the literal. Each field is one node, so ir_id and + // refs_id match. + auto refs = semantics_->GetNodeBlock(refs_id); + auto type_id = AddNode(SemanticsNode::StructType::Make( + parse_node, type_block_id, type_block_id)); + + auto value_id = AddNode( + SemanticsNode::StructValue::Make(parse_node, type_id, ir_id, refs_id)); + node_stack_.Push(parse_node, value_id); + return true; } auto SemanticsParseTreeHandler::HandleStructLiteralOrStructTypeLiteralStart( ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, - "HandleStructLiteralOrStructTypeLiteralStart"); - return false; + PushScope(); + node_stack_.Push(parse_node); + // At this point we aren't sure whether this will be a value or type literal, + // so we push onto args irrespective. It just won't be used for a type + // literal. + args_type_info_stack_.Push(); + ParamOrArgStart(); + return true; } auto SemanticsParseTreeHandler::HandleStructTypeLiteral( ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleStructTypeLiteral"); - return false; + auto [ir_id, refs_id] = ParamOrArgEnd( + /*for_args=*/false, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + + PopScope(); + node_stack_.PopAndDiscardSoloParseNode( + ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + // This is only used for value literals. + args_type_info_stack_.Pop(); + + CARBON_CHECK(refs_id != SemanticsNodeBlockId::Empty) + << "{} is handled by StructLiteral."; + + auto type_id = + AddNode(SemanticsNode::StructType::Make(parse_node, ir_id, refs_id)); + node_stack_.Push(parse_node, type_id); + return true; } auto SemanticsParseTreeHandler::HandleTemplate(ParseTree::Node parse_node) @@ -1015,16 +1141,17 @@ auto SemanticsParseTreeHandler::HandleVariableDeclaration( auto storage_id = node_stack_.PopForNodeId(ParseNodeKind::VariableInitializer); - auto binding = node_stack_.PopForParseNodeAndNameId(); + auto binding = + node_stack_.PopForParseNodeAndNameId(ParseNodeKind::PatternBinding); // Restore the name now that the initializer is complete. ReaddNameToLookup(binding.second, storage_id); - auto storage_type = - TryTypeConversion(parse_node, storage_id, last_child.second, - /*can_convert_lhs=*/false); - AddNode(SemanticsNode::Assign::Make(parse_node, storage_type, storage_id, - last_child.second)); + auto cast_value_id = ImplicitAs(parse_node, last_child.second, + semantics_->GetType(storage_id)); + AddNode(SemanticsNode::Assign::Make(parse_node, + semantics_->GetType(cast_value_id), + storage_id, cast_value_id)); } node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::VariableIntroducer); @@ -1046,7 +1173,8 @@ auto SemanticsParseTreeHandler::HandleVariableInitializer( // restored by `VariableDeclaration`. // Save the storage ID. - auto it = name_lookup_.find(node_stack_.PeekForNameId()); + auto it = name_lookup_.find( + node_stack_.PeekForNameId(ParseNodeKind::PatternBinding)); CARBON_CHECK(it != name_lookup_.end()); CARBON_CHECK(!it->second.empty()); auto storage_id = it->second.back(); diff --git a/toolchain/semantics/semantics_parse_tree_handler.h b/toolchain/semantics/semantics_parse_tree_handler.h index 20b0ed73488b..02f89fdbfe3a 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.h +++ b/toolchain/semantics/semantics_parse_tree_handler.h @@ -33,6 +33,8 @@ class SemanticsParseTreeHandler { node_block_stack_("node_block_stack_", semantics.node_blocks_, vlog_stream), params_or_args_stack_("params_or_args_stack_", semantics.node_blocks_, + vlog_stream), + args_type_info_stack_("args_type_info_stack_", semantics.node_blocks_, vlog_stream) {} // Outputs the ParseTree information into SemanticsIR. @@ -127,16 +129,37 @@ class SemanticsParseTreeHandler { ParseTree::Node param_parse_node, SemanticsNodeBlockId param_refs_id) -> bool; - auto ParamOrArgStart() -> void; - auto ParamOrArgComma(ParseTree::Node parse_node) -> bool; - auto ParamOrArgEnd( - ParseNodeKind start_kind, ParseNodeKind comma_kind, - std::function on_start) + // Runs ImplicitAs behavior to convert `value` to `as_type`, returning the + // result type. The result will be the node to use to replace `value`. The + // result will be BuiltinInvalidType for errors; this handles printing + // diagnostics. + auto ImplicitAs(ParseTree::Node parse_node, SemanticsNodeId value, + SemanticsNodeId as_type) -> SemanticsNodeId; + + // Returns true if the ImplicitAs can use struct conversion. + // TODO: This currently only supports struct types that precisely match. + auto CanImplicitAsStruct(SemanticsNode value_type, SemanticsNode as_type) -> bool; + // Starts handling parameters or arguments. + auto ParamOrArgStart() -> void; + + // On a comma, pushes the entry. On return, the top of node_stack_ will be + // start_kind. + auto ParamOrArgComma(bool for_args) -> void; + + // Detects whether there's an entry to push. On return, the top of + // node_stack_ will be start_kind, and the caller should do type-specific + // processing. Returns a pair of {ir_id, refs_id}. + auto ParamOrArgEnd(bool for_args, ParseNodeKind start_kind) + -> std::pair; + // Saves a parameter from the top block in node_stack_ to the top block in - // params_or_args_stack_. Returns false if nothing is copied. - auto ParamOrArgSave() -> bool; + // params_or_args_stack_. If for_args, adds a StubReference of the previous + // node's result to the IR. + // + // This should only be called by other ParamOrArg functions, not directly. + auto ParamOrArgSave(bool for_args) -> void; // Parse node handlers. Returns false for unrecoverable errors. #define CARBON_PARSE_NODE_KIND(Name) \ @@ -172,6 +195,12 @@ class SemanticsParseTreeHandler { // node in blocks here. SemanticsNodeBlockStack params_or_args_stack_; + // The stack of node blocks being used for type information while processing + // arguments. This is used in parallel with params_or_args_stack_. It's + // currently only used for struct literals, where we need to track names + // for a type separate from the literal arguments. + SemanticsNodeBlockStack args_type_info_stack_; + // Completed parameters that are held temporarily on a side-channel for a // function. This can't use node_stack_ because it has space for only one // value, whereas parameters return two values. diff --git a/toolchain/semantics/testdata/basics/builtin_nodes.carbon b/toolchain/semantics/testdata/basics/builtin_nodes.carbon index 2ba79471f120..b55ff2042351 100644 --- a/toolchain/semantics/testdata/basics/builtin_nodes.carbon +++ b/toolchain/semantics/testdata/basics/builtin_nodes.carbon @@ -22,6 +22,8 @@ // CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeIntegerType, type: nodeTypeType}, // CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeFloatingPointType, type: nodeTypeType}, // CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeStringType, type: nodeTypeType}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeEmptyStructType, type: nodeTypeType}, +// CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeEmptyStruct, type: nodeEmptyStructType}, // CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeEmptyTupleType, type: nodeTypeType}, // CHECK:STDOUT: {kind: CrossReference, arg0: ir0, arg1: nodeEmptyTuple, type: nodeEmptyTupleType}, // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/call/empty_struct.carbon b/toolchain/semantics/testdata/function/call/empty_struct.carbon new file mode 100644 index 000000000000..482a7629c151 --- /dev/null +++ b/toolchain/semantics/testdata/function/call/empty_struct.carbon @@ -0,0 +1,66 @@ +// 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: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: {arg_ir: block4, arg_refs: block5}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: {param_ir: block1, param_refs: block2}, +// CHECK:STDOUT: {param_ir: block0, param_refs: block0}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: a, +// CHECK:STDOUT: Echo, +// CHECK:STDOUT: Main, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: VarStorage, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node+0, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str1, arg1: callable0}, +// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+2, arg1: block0}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str2, arg1: callable1}, +// CHECK:STDOUT: {kind: StubReference, arg0: nodeEmptyStruct, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: Call, arg0: call0, arg1: callable0, type: nodeEmptyTuple}, +// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+4, arg1: block6}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +fn Echo(a: {}) { +} + +fn Main() { + Echo({}); +} diff --git a/toolchain/semantics/testdata/function/call/fail_param_count.carbon b/toolchain/semantics/testdata/function/call/fail_param_count.carbon index 8e9ad2a55d0d..59113d92e23a 100644 --- a/toolchain/semantics/testdata/function/call/fail_param_count.carbon +++ b/toolchain/semantics/testdata/function/call/fail_param_count.carbon @@ -46,11 +46,17 @@ // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+10, arg1: block0}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str5, arg1: callable3}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+13, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+15, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int2, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+17, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int3, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+19, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int4, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+21, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int5, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+23, type: nodeIntegerType}, // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+12, arg1: block0}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ @@ -64,7 +70,7 @@ // CHECK:STDOUT: node+10, // CHECK:STDOUT: node+11, // CHECK:STDOUT: node+12, -// CHECK:STDOUT: node+19, +// CHECK:STDOUT: node+25, // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+2, @@ -85,32 +91,38 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+13, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+14, // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+14, -// CHECK:STDOUT: node+15, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+14, // CHECK:STDOUT: node+15, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ // CHECK:STDOUT: node+16, // CHECK:STDOUT: node+17, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+16, -// CHECK:STDOUT: node+17, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ // CHECK:STDOUT: node+18, // CHECK:STDOUT: ], // CHECK:STDOUT: [ +// CHECK:STDOUT: node+16, // CHECK:STDOUT: node+18, // CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+19, +// CHECK:STDOUT: node+20, +// CHECK:STDOUT: node+21, +// CHECK:STDOUT: node+22, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+20, +// CHECK:STDOUT: node+22, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+23, +// CHECK:STDOUT: node+24, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+24, +// CHECK:STDOUT: ], // CHECK:STDOUT: ] fn Run0() {} diff --git a/toolchain/semantics/testdata/function/call/fail_param_type.carbon b/toolchain/semantics/testdata/function/call/fail_param_type.carbon index 119243483251..1e172265cd4e 100644 --- a/toolchain/semantics/testdata/function/call/fail_param_type.carbon +++ b/toolchain/semantics/testdata/function/call/fail_param_type.carbon @@ -28,6 +28,7 @@ // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+2, arg1: block0}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str2, arg1: callable1}, // CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+5, type: nodeFloatingPointType}, // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+4, arg1: block0}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ @@ -44,13 +45,14 @@ // CHECK:STDOUT: node+2, // CHECK:STDOUT: node+3, // CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+5, // CHECK:STDOUT: node+6, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+5, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, // CHECK:STDOUT: ], // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/call/more_param_ir.carbon b/toolchain/semantics/testdata/function/call/more_param_ir.carbon index 08cb2b1209b8..db24fee8b340 100644 --- a/toolchain/semantics/testdata/function/call/more_param_ir.carbon +++ b/toolchain/semantics/testdata/function/call/more_param_ir.carbon @@ -44,10 +44,13 @@ // CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+9, arg1: node+10, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int2, type: nodeIntegerType}, // CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+11, arg1: node+12, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+13, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int3, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int4, type: nodeIntegerType}, -// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+14, arg1: node+15, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+15, arg1: node+16, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+17, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int5, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+19, type: nodeIntegerType}, // CHECK:STDOUT: {kind: Call, arg0: call0, arg1: callable0, type: nodeEmptyTuple}, // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+8, arg1: block6}, // CHECK:STDOUT: ] @@ -71,7 +74,7 @@ // CHECK:STDOUT: node+6, // CHECK:STDOUT: node+7, // CHECK:STDOUT: node+8, -// CHECK:STDOUT: node+19, +// CHECK:STDOUT: node+22, // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+9, @@ -83,14 +86,17 @@ // CHECK:STDOUT: node+15, // CHECK:STDOUT: node+16, // CHECK:STDOUT: node+17, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+13, -// CHECK:STDOUT: node+16, -// CHECK:STDOUT: node+17, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ // CHECK:STDOUT: node+18, +// CHECK:STDOUT: node+19, +// CHECK:STDOUT: node+20, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+14, +// CHECK:STDOUT: node+18, +// CHECK:STDOUT: node+20, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+21, // CHECK:STDOUT: ], // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/call/params_one.carbon b/toolchain/semantics/testdata/function/call/params_one.carbon index eebc96cfe3d9..51369a24c5d7 100644 --- a/toolchain/semantics/testdata/function/call/params_one.carbon +++ b/toolchain/semantics/testdata/function/call/params_one.carbon @@ -29,6 +29,7 @@ // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+2, arg1: block0}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str2, arg1: callable1}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+5, type: nodeIntegerType}, // CHECK:STDOUT: {kind: Call, arg0: call0, arg1: callable0, type: nodeEmptyTuple}, // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+4, arg1: block6}, // CHECK:STDOUT: ] @@ -46,17 +47,18 @@ // CHECK:STDOUT: node+2, // CHECK:STDOUT: node+3, // CHECK:STDOUT: node+4, -// CHECK:STDOUT: node+7, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+8, // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+6, // CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: ], // CHECK:STDOUT: ] fn Foo(a: i32) {} diff --git a/toolchain/semantics/testdata/function/call/params_one_comma.carbon b/toolchain/semantics/testdata/function/call/params_one_comma.carbon index 89a0c3aaa07c..b2fad16c30a9 100644 --- a/toolchain/semantics/testdata/function/call/params_one_comma.carbon +++ b/toolchain/semantics/testdata/function/call/params_one_comma.carbon @@ -31,8 +31,10 @@ // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+2, arg1: block0}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str2, arg1: callable1}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+5, type: nodeIntegerType}, // CHECK:STDOUT: {kind: Call, arg0: call0, arg1: callable0, type: nodeEmptyTuple}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: nodeIntegerType}, // CHECK:STDOUT: {kind: Call, arg0: call1, arg1: callable0, type: nodeEmptyTuple}, // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+4, arg1: block6}, // CHECK:STDOUT: ] @@ -50,23 +52,25 @@ // CHECK:STDOUT: node+2, // CHECK:STDOUT: node+3, // CHECK:STDOUT: node+4, -// CHECK:STDOUT: node+9, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+11, // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ // CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+9, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+7, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+9, // CHECK:STDOUT: ], // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/call/params_two.carbon b/toolchain/semantics/testdata/function/call/params_two.carbon index f9f004dd56a8..cb9c1ae34499 100644 --- a/toolchain/semantics/testdata/function/call/params_two.carbon +++ b/toolchain/semantics/testdata/function/call/params_two.carbon @@ -33,7 +33,9 @@ // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+4, arg1: block0}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str3, arg1: callable1}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+7, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+9, type: nodeIntegerType}, // CHECK:STDOUT: {kind: Call, arg0: call0, arg1: callable0, type: nodeEmptyTuple}, // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+6, arg1: block6}, // CHECK:STDOUT: ] @@ -54,18 +56,20 @@ // CHECK:STDOUT: node+4, // CHECK:STDOUT: node+5, // CHECK:STDOUT: node+6, +// CHECK:STDOUT: node+12, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+9, // CHECK:STDOUT: node+10, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+7, // CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+10, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+7, -// CHECK:STDOUT: node+8, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+11, // CHECK:STDOUT: ], // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/call/params_two_comma.carbon b/toolchain/semantics/testdata/function/call/params_two_comma.carbon index 85ef89fb6df8..c5c2dc0251ee 100644 --- a/toolchain/semantics/testdata/function/call/params_two_comma.carbon +++ b/toolchain/semantics/testdata/function/call/params_two_comma.carbon @@ -36,10 +36,14 @@ // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+4, arg1: block0}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str3, arg1: callable1}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+7, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+9, type: nodeIntegerType}, // CHECK:STDOUT: {kind: Call, arg0: call0, arg1: callable0, type: nodeEmptyTuple}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int2, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+12, type: nodeIntegerType}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int3, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+14, type: nodeIntegerType}, // CHECK:STDOUT: {kind: Call, arg0: call1, arg1: callable0, type: nodeEmptyTuple}, // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+6, arg1: block6}, // CHECK:STDOUT: ] @@ -60,27 +64,31 @@ // CHECK:STDOUT: node+4, // CHECK:STDOUT: node+5, // CHECK:STDOUT: node+6, -// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+17, // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+7, // CHECK:STDOUT: node+8, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+7, -// CHECK:STDOUT: node+8, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ // CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+11, +// CHECK:STDOUT: node+16, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ // CHECK:STDOUT: node+12, +// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+14, +// CHECK:STDOUT: node+15, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+10, -// CHECK:STDOUT: node+11, -// CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+10, -// CHECK:STDOUT: node+11, +// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+15, // CHECK:STDOUT: ], // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/empty.carbon b/toolchain/semantics/testdata/struct/empty.carbon new file mode 100644 index 000000000000..765efd01ae91 --- /dev/null +++ b/toolchain/semantics/testdata/struct/empty.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: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: x, +// CHECK:STDOUT: y, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: VarStorage, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node+0, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: Assign, arg0: node+0, arg1: nodeEmptyStruct, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: VarStorage, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+3, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: Assign, arg0: node+3, arg1: node+0, type: nodeEmptyStructType}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +var x: {} = {}; +var y: {} = x; diff --git a/toolchain/semantics/testdata/struct/fail_assign_empty.carbon b/toolchain/semantics/testdata/struct/fail_assign_empty.carbon new file mode 100644 index 000000000000..9191d55bc32d --- /dev/null +++ b/toolchain/semantics/testdata/struct/fail_assign_empty.carbon @@ -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 +// +// AUTOUPDATE +// RUN: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: a, +// CHECK:STDOUT: x, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block1, arg1: block2, type: nodeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: node+1}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+2, type: node+1}, +// CHECK:STDOUT: {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_assign_empty.carbon:[[@LINE+1]]:22: Cannot implicitly convert from {} as Type to {.a: i32}. +var x: {.a: i32} = {}; diff --git a/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon b/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon new file mode 100644 index 000000000000..a2c8c5687e42 --- /dev/null +++ b/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon @@ -0,0 +1,54 @@ +// 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: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 1, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: x, +// CHECK:STDOUT: a, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: VarStorage, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node+0, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+2, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block3, arg1: block3, type: nodeTypeType}, +// CHECK:STDOUT: {kind: StructValue, arg0: block2, arg1: block4, type: node+5}, +// CHECK:STDOUT: {kind: Assign, arg0: node+0, arg1: nodeInvalidType, type: nodeInvalidType}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon:[[@LINE+1]]:21: Cannot implicitly convert from {.a: i32} to {} as Type. +var x: {} = {.a = 1}; diff --git a/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon b/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon new file mode 100644 index 000000000000..070080b5cf16 --- /dev/null +++ b/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon @@ -0,0 +1,64 @@ +// 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: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 1, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: a, +// CHECK:STDOUT: x, +// CHECK:STDOUT: b, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block1, arg1: block2, type: nodeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: node+1}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+2, type: node+1}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str2, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+4, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block5, arg1: block5, type: nodeTypeType}, +// CHECK:STDOUT: {kind: StructValue, arg0: block4, arg1: block6, type: node+7}, +// CHECK:STDOUT: {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon:[[@LINE+1]]:28: Cannot implicitly convert from {.b: i32} to {.a: i32}. +var x: {.a: i32} = {.b = 1}; diff --git a/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon b/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon new file mode 100644 index 000000000000..c326bd11233d --- /dev/null +++ b/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon @@ -0,0 +1,64 @@ +// 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: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: {mantissa: 10, exponent: -1, is_decimal: 1}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: a, +// CHECK:STDOUT: x, +// CHECK:STDOUT: b, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block1, arg1: block2, type: nodeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: node+1}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+2, type: node+1}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str2, type: nodeFloatingPointType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+4, type: nodeFloatingPointType}, +// CHECK:STDOUT: {kind: StructType, arg0: block5, arg1: block5, type: nodeTypeType}, +// CHECK:STDOUT: {kind: StructValue, arg0: block4, arg1: block6, type: node+7}, +// CHECK:STDOUT: {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon:[[@LINE+1]]:30: Cannot implicitly convert from {.b: f64} to {.a: i32}. +var x: {.a: i32} = {.b = 1.0}; diff --git a/toolchain/semantics/testdata/struct/fail_too_few_values.carbon b/toolchain/semantics/testdata/struct/fail_too_few_values.carbon new file mode 100644 index 000000000000..28443ed8482e --- /dev/null +++ b/toolchain/semantics/testdata/struct/fail_too_few_values.carbon @@ -0,0 +1,67 @@ +// 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: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 1, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: a, +// CHECK:STDOUT: b, +// CHECK:STDOUT: x, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block1, arg1: block2, type: nodeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: node+2}, +// CHECK:STDOUT: {kind: BindName, arg0: str2, arg1: node+3, type: node+2}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+5, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block5, arg1: block5, type: nodeTypeType}, +// CHECK:STDOUT: {kind: StructValue, arg0: block4, arg1: block6, type: node+8}, +// CHECK:STDOUT: {kind: Assign, arg0: node+3, arg1: nodeInvalidType, type: nodeInvalidType}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_too_few_values.carbon:[[@LINE+1]]:37: Cannot implicitly convert from {.a: i32} to {.a: i32, .b: i32}. +var x: {.a: i32, .b: i32} = {.a = 1}; diff --git a/toolchain/semantics/testdata/struct/fail_type_assign.carbon b/toolchain/semantics/testdata/struct/fail_type_assign.carbon new file mode 100644 index 000000000000..944f4d79233a --- /dev/null +++ b/toolchain/semantics/testdata/struct/fail_type_assign.carbon @@ -0,0 +1,54 @@ +// 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: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: a, +// CHECK:STDOUT: x, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block1, arg1: block2, type: nodeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: node+1}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+2, type: node+1}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block4, arg1: block5, type: nodeTypeType}, +// CHECK:STDOUT: {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_type_assign.carbon:[[@LINE+1]]:29: Cannot implicitly convert from Type to {.a: i32}. +var x: {.a: i32} = {.a: i32}; diff --git a/toolchain/semantics/testdata/struct/fail_value_as_type.carbon b/toolchain/semantics/testdata/struct/fail_value_as_type.carbon new file mode 100644 index 000000000000..361e19a55bff --- /dev/null +++ b/toolchain/semantics/testdata/struct/fail_value_as_type.carbon @@ -0,0 +1,52 @@ +// 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: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 1, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: a, +// CHECK:STDOUT: x, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block2, arg1: block2, type: nodeTypeType}, +// CHECK:STDOUT: {kind: StructValue, arg0: block1, arg1: block3, type: node+3}, +// CHECK:STDOUT: {kind: VarStorage, type: nodeInvalidType}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+5, type: nodeInvalidType}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_value_as_type.carbon:[[@LINE+1]]:15: Cannot implicitly convert from {.a: i32} to Type. +var x: {.a = 1}; diff --git a/toolchain/semantics/testdata/struct/one_entry.carbon b/toolchain/semantics/testdata/struct/one_entry.carbon new file mode 100644 index 000000000000..e48f76eccb47 --- /dev/null +++ b/toolchain/semantics/testdata/struct/one_entry.carbon @@ -0,0 +1,79 @@ +// 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: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 4, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: a, +// CHECK:STDOUT: x, +// CHECK:STDOUT: y, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block1, arg1: block2, type: nodeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: node+1}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+2, type: node+1}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+4, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block5, arg1: block5, type: nodeTypeType}, +// CHECK:STDOUT: {kind: StructValue, arg0: block4, arg1: block6, type: node+7}, +// CHECK:STDOUT: {kind: Assign, arg0: node+2, arg1: node+8, type: node+7}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block7, arg1: block8, type: nodeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: node+11}, +// CHECK:STDOUT: {kind: BindName, arg0: str2, arg1: node+12, type: node+11}, +// CHECK:STDOUT: {kind: Assign, arg0: node+12, arg1: node+2, type: node+1}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+11, +// CHECK:STDOUT: node+12, +// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+14, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +var x: {.a: i32} = {.a = 4}; +var y: {.a: i32} = x; diff --git a/toolchain/semantics/testdata/struct/two_entries.carbon b/toolchain/semantics/testdata/struct/two_entries.carbon new file mode 100644 index 000000000000..20e4fdb0df09 --- /dev/null +++ b/toolchain/semantics/testdata/struct/two_entries.carbon @@ -0,0 +1,94 @@ +// 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: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 1, +// CHECK:STDOUT: 2, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: a, +// CHECK:STDOUT: b, +// CHECK:STDOUT: x, +// CHECK:STDOUT: y, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block1, arg1: block2, type: nodeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: node+2}, +// CHECK:STDOUT: {kind: BindName, arg0: str2, arg1: node+3, type: node+2}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+5, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block5, arg1: block5, type: nodeTypeType}, +// CHECK:STDOUT: {kind: StructValue, arg0: block4, arg1: block6, type: node+11}, +// CHECK:STDOUT: {kind: Assign, arg0: node+3, arg1: node+12, type: node+11}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructTypeField, arg0: str1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StructType, arg0: block7, arg1: block8, type: nodeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: node+16}, +// CHECK:STDOUT: {kind: BindName, arg0: str3, arg1: node+17, type: node+16}, +// CHECK:STDOUT: {kind: Assign, arg0: node+17, arg1: node+3, type: node+2}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+11, +// CHECK:STDOUT: node+12, +// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+16, +// CHECK:STDOUT: node+17, +// CHECK:STDOUT: node+18, +// CHECK:STDOUT: node+19, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+14, +// CHECK:STDOUT: node+15, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+14, +// CHECK:STDOUT: node+15, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +var x: {.a: i32, .b: i32} = {.a = 1, .b = 2}; +var y: {.a: i32, .b: i32} = x; diff --git a/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon b/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon index 2e31f5a1d640..4103e902c164 100644 --- a/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon +++ b/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon @@ -24,7 +24,7 @@ // CHECK:STDOUT: {kind: VarStorage, type: nodeIntegerType}, // CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+1, type: nodeIntegerType}, // CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: nodeFloatingPointType}, -// CHECK:STDOUT: {kind: Assign, arg0: node+1, arg1: node+3, type: nodeInvalidType}, +// CHECK:STDOUT: {kind: Assign, arg0: node+1, arg1: nodeInvalidType, type: nodeInvalidType}, // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+0, arg1: block2}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ @@ -43,6 +43,6 @@ // CHECK:STDOUT: ] fn Main() { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon:[[@LINE+1]]:19: Type mismatch: lhs is i32, rhs is f64 + // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon:[[@LINE+1]]:19: Cannot implicitly convert from f64 to i32. var x: i32 = 1.0; } diff --git a/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon b/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon new file mode 100644 index 000000000000..79086593e645 --- /dev/null +++ b/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon @@ -0,0 +1,51 @@ +// 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: %{not} %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: calls: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: callables: [ +// CHECK:STDOUT: {param_ir: block0, param_refs: block0}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 1, +// CHECK:STDOUT: 1, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: Main, +// CHECK:STDOUT: x, +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str0, arg1: callable0}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: VarStorage, type: nodeInvalidType}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+2, type: nodeInvalidType}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: Assign, arg0: node+2, arg1: nodeInvalidType, type: nodeInvalidType}, +// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+0, arg1: block2}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] + +fn Main() { + // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon:[[@LINE+1]]:10: Cannot implicitly convert from i32 to Type. + var x: 1 = 1; +}