Canonicalize struct types. (#2855)

This adds canonicalization of struct types based on their type fields. It obsoletes the current CanImplicitAsStruct because the type ids should now be identical when they're structurally identical; there's only a reason to implicit CanImplicitAsStruct to detect _compatible_ conversions.

The type fields themselves aren't canonicalized because it would need to be done during the first parse, and could yield name conflicts being associated with the wrong location. i.e.:

```
var x: {a: i32, a: i32};
var y: {a: i32, b: i32, a: i32};
```

This should yield two separate name conflict diagnostics pointing at the type fields for each respective line, but if struct type fields were canonicalized then both would point at the first `a: i32` field definition. This isn't expected to be an issue for types because I'm trying to print those, but we may also end up with a "first defined at" situation in some cases (still, less confusing because the type should match). Regardless, I think individual fields gets much more awkward.
This commit is contained in:
Jon Ross-Perkins
2023-05-26 14:42:45 -07:00
committed by GitHub
parent 1497e1333d
commit 2e4beaf8f0
16 changed files with 133 additions and 161 deletions
@@ -74,13 +74,7 @@ auto SemanticsHandleStructLiteral(SemanticsContext& context,
ParseNodeKind::StructLiteralOrStructTypeLiteralStart);
auto type_block_id = context.args_type_info_stack().Pop();
// Construct a type for the literal.
// TODO: This should try to canonicalize the struct form before adding the
// node.
auto refs = context.semantics().GetNodeBlock(refs_id);
auto type_id =
context.CanonicalizeType(context.AddNode(SemanticsNode::StructType::Make(
parse_node, SemanticsTypeId::TypeType, type_block_id)));
auto type_id = context.CanonicalizeStructType(parse_node, type_block_id);
auto value_id = context.AddNode(
SemanticsNode::StructValue::Make(parse_node, type_id, refs_id));
@@ -114,9 +108,8 @@ auto SemanticsHandleStructTypeLiteral(SemanticsContext& context,
CARBON_CHECK(refs_id != SemanticsNodeBlockId::Empty)
<< "{} is handled by StructLiteral.";
auto type_id = context.AddNode(SemanticsNode::StructType::Make(
parse_node, SemanticsTypeId::TypeType, refs_id));
context.node_stack().Push(parse_node, type_id);
auto type_id = context.CanonicalizeStructType(parse_node, refs_id);
context.node_stack().Push(parse_node, context.semantics().GetType(type_id));
return true;
}