Support designator expressions on structs. (#2716)

This commit is contained in:
Jon Ross-Perkins
2023-03-30 14:19:46 -07:00
committed by GitHub
parent 807ef98758
commit 706e611b6d
10 changed files with 341 additions and 2 deletions
@@ -103,6 +103,8 @@ CARBON_DIAGNOSTIC_KIND(ReturnStatementImplicitNote)
CARBON_DIAGNOSTIC_KIND(ReturnStatementMissingExpression)
CARBON_DIAGNOSTIC_KIND(ReturnStatementTypeMismatch)
CARBON_DIAGNOSTIC_KIND(ImplicitAsConversionFailure)
CARBON_DIAGNOSTIC_KIND(DesignatorExpressionUnsupported)
CARBON_DIAGNOSTIC_KIND(DesignatorExpressionNameNotFound)
// ============================================================================
// Other diagnostics
+5
View File
@@ -176,6 +176,11 @@ auto Lowering::HandleStringLiteralNode(SemanticsNodeId /*node_id*/,
CARBON_FATAL() << "TODO: Add support: " << node;
}
auto Lowering::HandleStructMemberAccessNode(SemanticsNodeId /*node_id*/,
SemanticsNode node) -> void {
CARBON_FATAL() << "TODO: Add support: " << node;
}
auto Lowering::HandleStructTypeNode(SemanticsNodeId /*node_id*/,
SemanticsNode node) -> void {
CARBON_FATAL() << "TODO: Add support: " << node;
+1
View File
@@ -159,6 +159,7 @@ auto SemanticsIR::StringifyNodeImpl(llvm::raw_ostream& out,
case SemanticsNodeKind::Return:
case SemanticsNodeKind::ReturnExpression:
case SemanticsNodeKind::StringLiteral:
case SemanticsNodeKind::StructMemberAccess:
case SemanticsNodeKind::StructValue:
case SemanticsNodeKind::StubReference:
case SemanticsNodeKind::VarStorage:
+13
View File
@@ -124,6 +124,15 @@ struct SemanticsStringId : public IndexBase {
}
};
// An index for member access.
struct SemanticsMemberIndex : public IndexBase {
using IndexBase::IndexBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "member";
IndexBase::Print(out);
}
};
// The standard structure for SemanticsNode. This is trying to provide a minimal
// amount of information for a node:
//
@@ -299,6 +308,10 @@ class SemanticsNode {
SemanticsBuiltinKind::StringType.AsInt(),
SemanticsStringId /*string_id*/>;
using StructMemberAccess = Factory<SemanticsNodeKind::StructMemberAccess,
SemanticsNodeId /*struct_id*/,
SemanticsMemberIndex /*ref_index*/>;
using StructType = FactoryPreTyped<
SemanticsNodeKind::StructType, SemanticsBuiltinKind::TypeType.AsInt(),
SemanticsNodeBlockId /*ir_id*/, SemanticsNodeBlockId /*refs_id*/>;
@@ -33,6 +33,7 @@ CARBON_SEMANTICS_NODE_KIND(RealLiteral)
CARBON_SEMANTICS_NODE_KIND(Return)
CARBON_SEMANTICS_NODE_KIND(ReturnExpression)
CARBON_SEMANTICS_NODE_KIND(StringLiteral)
CARBON_SEMANTICS_NODE_KIND(StructMemberAccess)
CARBON_SEMANTICS_NODE_KIND(StructType)
CARBON_SEMANTICS_NODE_KIND(StructTypeField)
CARBON_SEMANTICS_NODE_KIND(StructValue)
@@ -495,8 +495,47 @@ auto SemanticsParseTreeHandler::HandleDesignatedName(ParseTree::Node parse_node)
auto SemanticsParseTreeHandler::HandleDesignatorExpression(
ParseTree::Node parse_node) -> bool {
emitter_->Emit(parse_node, SemanticsTodo, "HandleDesignatorExpression");
return false;
auto [_, name_id] =
node_stack_.PopForParseNodeAndNameId(ParseNodeKind::DesignatedName);
auto base_id = node_stack_.PopForNodeId();
auto base = semantics_->GetNode(base_id);
auto base_type = semantics_->GetNode(base.type_id());
switch (base_type.kind()) {
case SemanticsNodeKind::StructType: {
auto refs = semantics_->GetNodeBlock(base_type.GetAsStructType().second);
// TODO: Do we need to optimize this with a lookup table for O(1)?
for (int i = 0; i < static_cast<int>(refs.size()); ++i) {
auto ref = semantics_->GetNode(refs[i]);
if (name_id == ref.GetAsStructTypeField()) {
AddNodeAndPush(parse_node, SemanticsNode::StructMemberAccess::Make(
parse_node, ref.type_id(), base_id,
SemanticsMemberIndex(i)));
return true;
}
}
CARBON_DIAGNOSTIC(DesignatorExpressionNameNotFound, Error,
"Type `{0}` does not have a member `{1}`.", std::string,
llvm::StringRef);
emitter_->Emit(parse_node, DesignatorExpressionNameNotFound,
semantics_->StringifyNode(base.type_id()),
semantics_->GetString(name_id));
break;
}
default: {
CARBON_DIAGNOSTIC(DesignatorExpressionUnsupported, Error,
"Type `{0}` does not support designator expressions.",
std::string);
emitter_->Emit(parse_node, DesignatorExpressionUnsupported,
semantics_->StringifyNode(base.type_id()));
break;
}
}
// Should only be reached on error.
node_stack_.Push(parse_node, SemanticsNodeId::BuiltinInvalidType);
return true;
}
auto SemanticsParseTreeHandler::HandleEmptyDeclaration(
@@ -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: %{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: x,
// CHECK:STDOUT: y,
// CHECK:STDOUT: b,
// CHECK:STDOUT: ]
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: VarStorage, type: nodeIntegerType},
// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType},
// CHECK:STDOUT: {kind: VarStorage, type: nodeIntegerType},
// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+2, type: nodeIntegerType},
// 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: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
var x: i32;
// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/designators/fail_unsupported.carbon:[[@LINE+1]]:15: Type `i32` does not support designator expressions.
var y: i32 = x.b;
@@ -0,0 +1,72 @@
// 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: 40, exponent: -1, is_decimal: 1},
// CHECK:STDOUT: ]
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: a,
// CHECK:STDOUT: x,
// CHECK:STDOUT: y,
// CHECK:STDOUT: b,
// CHECK:STDOUT: ]
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeFloatingPointType},
// 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: str0, 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: node+8, type: node+7},
// CHECK:STDOUT: {kind: VarStorage, type: nodeIntegerType},
// CHECK:STDOUT: {kind: BindName, arg0: str2, arg1: node+10, type: nodeIntegerType},
// CHECK:STDOUT: {kind: Assign, arg0: node+10, 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: node+10,
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: node+12,
// 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: ]
var x: {.a: f64} = {.a = 4.0};
// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_member_access_type.carbon:[[@LINE+1]]:15: Type `{.a: f64}` does not have a member `b`.
var y: i32 = x.b;
@@ -0,0 +1,72 @@
// 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: 4,
// CHECK:STDOUT: ]
// CHECK:STDOUT: real_literals: [
// CHECK:STDOUT: ]
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: a,
// CHECK:STDOUT: x,
// CHECK:STDOUT: y,
// 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: 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: VarStorage, type: nodeIntegerType},
// CHECK:STDOUT: {kind: BindName, arg0: str2, arg1: node+10, type: nodeIntegerType},
// CHECK:STDOUT: {kind: Assign, arg0: node+10, 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: node+10,
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: node+12,
// 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: ]
var x: {.a: i32} = {.a = 4};
// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_non_member_access.carbon:[[@LINE+1]]:15: Type `{.a: i32}` does not have a member `b`.
var y: i32 = x.b;
@@ -0,0 +1,92 @@
// 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: ]
// CHECK:STDOUT: real_literals: [
// CHECK:STDOUT: {mantissa: 0, exponent: -1, is_decimal: 1},
// CHECK:STDOUT: ]
// CHECK:STDOUT: strings: [
// CHECK:STDOUT: a,
// CHECK:STDOUT: b,
// CHECK:STDOUT: x,
// CHECK:STDOUT: y,
// CHECK:STDOUT: z,
// CHECK:STDOUT: ]
// CHECK:STDOUT: nodes: [
// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeFloatingPointType},
// 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: RealLiteral, arg0: real0, type: nodeFloatingPointType},
// CHECK:STDOUT: {kind: StructTypeField, arg0: str0, type: nodeFloatingPointType},
// CHECK:STDOUT: {kind: StubReference, arg0: node+5, type: nodeFloatingPointType},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, 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: VarStorage, type: nodeIntegerType},
// CHECK:STDOUT: {kind: BindName, arg0: str3, arg1: node+14, type: nodeIntegerType},
// CHECK:STDOUT: {kind: StructMemberAccess, arg0: node+3, arg1: member1, type: nodeIntegerType},
// CHECK:STDOUT: {kind: Assign, arg0: node+14, arg1: node+16, type: nodeIntegerType},
// CHECK:STDOUT: {kind: VarStorage, type: nodeIntegerType},
// CHECK:STDOUT: {kind: BindName, arg0: str4, arg1: node+18, type: nodeIntegerType},
// CHECK:STDOUT: {kind: Assign, arg0: node+18, arg1: node+14, type: nodeIntegerType},
// 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+14,
// CHECK:STDOUT: node+15,
// CHECK:STDOUT: node+16,
// CHECK:STDOUT: node+17,
// CHECK:STDOUT: node+18,
// CHECK:STDOUT: node+19,
// CHECK:STDOUT: node+20,
// 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: ]
var x: {.a: f64, .b: i32} = {.a = 0.0, .b = 1};
var y: i32 = x.b;
var z: i32 = y;