소스 검색

Remove the builtin empty tuple value (not type). (#2850)

We do use the empty tuple type for function returns, so I don't want to get rid of it, but the value is unused. With this change, builtins are all types. Long-term the empty tuple value should have a representation similar to structs; just a tuple value that's empty, not a built-in.
Jon Ross-Perkins 2 년 전
부모
커밋
709412ca97

+ 0 - 1
toolchain/driver/testdata/semantics_builtin_nodes.carbon

@@ -22,7 +22,6 @@
 // CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeFloatingPointType, 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: nodeStringType, type: nodeTypeType},
 // CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeEmptyTupleType, type: nodeTypeType},
 // CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeEmptyTupleType, type: nodeTypeType},
-// CHECK:STDOUT:   {kind: CrossReference, arg0: ir0, arg1: nodeEmptyTuple, type: nodeEmptyTupleType},
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: ]
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT: node_blocks: [
 // CHECK:STDOUT:   [
 // CHECK:STDOUT:   [

+ 5 - 17
toolchain/lowering/lowering_context.cpp

@@ -111,23 +111,11 @@ auto LoweringContext::GetLoweredNodeAsType(SemanticsNodeId node_id)
 auto LoweringContext::GetLoweredNodeAsValue(SemanticsNodeId node_id)
 auto LoweringContext::GetLoweredNodeAsValue(SemanticsNodeId node_id)
     -> llvm::Value* {
     -> llvm::Value* {
   auto& node = lowered_nodes_[node_id.index];
   auto& node = lowered_nodes_[node_id.index];
-  if (node.is<llvm::Value*>()) {
-    return node.get<llvm::Value*>();
-  }
-  CARBON_CHECK(node.isNull())
-      << node_id << " is already set as a type, not a value";
-  // Empty values are built lazily.
-  // TODO: It might be better to built them at initialization, putting them in
-  // every IR even if not used. This is probably a performance decision since it
-  // would simplify this function.
-  if (node_id == SemanticsNodeId::BuiltinEmptyTuple) {
-    auto* type = GetLoweredNodeAsType(SemanticsNodeId::BuiltinEmptyTupleType);
-    auto* value = llvm::ConstantStruct::get(llvm::cast<llvm::StructType>(type),
-                                            llvm::ArrayRef<llvm::Constant*>());
-    node = value;
-    return value;
-  }
-  CARBON_FATAL() << node_id << " is null, cannot be initialized";
+  auto* value = node.dyn_cast<llvm::Value*>();
+  CARBON_CHECK(value != nullptr)
+      << node_id << " doesn't have a Value (either Type or null); nullness: "
+      << node.isNull();
+  return value;
 }
 }
 
 
 }  // namespace Carbon
 }  // namespace Carbon

+ 1 - 1
toolchain/semantics/semantics_builtin_kind.cpp

@@ -14,7 +14,7 @@ CARBON_DEFINE_ENUM_CLASS_NAMES(SemanticsBuiltinKind) = {
 
 
 auto SemanticsBuiltinKind::label() -> llvm::StringRef {
 auto SemanticsBuiltinKind::label() -> llvm::StringRef {
   static constexpr llvm::StringLiteral Labels[] = {
   static constexpr llvm::StringLiteral Labels[] = {
-#define CARBON_SEMANTICS_BUILTIN_KIND(Name, Type, Label) Label,
+#define CARBON_SEMANTICS_BUILTIN_KIND(Name, Label) Label,
 #include "toolchain/semantics/semantics_builtin_kind.def"
 #include "toolchain/semantics/semantics_builtin_kind.def"
   };
   };
   return Labels[AsInt()];
   return Labels[AsInt()];

+ 9 - 13
toolchain/semantics/semantics_builtin_kind.def

@@ -11,9 +11,9 @@
 // - CARBON_SEMANTICS_BUILTIN_KIND_NAME(Name)
 // - CARBON_SEMANTICS_BUILTIN_KIND_NAME(Name)
 //   Used as a fallback if other macros are missing. Used directly by Invalid
 //   Used as a fallback if other macros are missing. Used directly by Invalid
 //   only, which is defined last.
 //   only, which is defined last.
-//   - CARBON_SEMANTICS_BUILTIN_KIND(Name, Type, Label)
-//     Defines a builtin kind with the associated type, which must also be
-//     builtin.
+//   - CARBON_SEMANTICS_BUILTIN_KIND(Name, Label)
+//     Defines a non-Invalid builtin type. The label is used for stringifying
+//     types.
 //
 //
 // This tree represents the subset relationship between these macros, where if a
 // This tree represents the subset relationship between these macros, where if a
 // specific x-macro isn't defined, it'll fall back to the parent macro.
 // specific x-macro isn't defined, it'll fall back to the parent macro.
@@ -38,12 +38,11 @@
 
 
 // Tracks expressions which are valid as types.
 // Tracks expressions which are valid as types.
 // This has a deliberately self-referential type.
 // This has a deliberately self-referential type.
-CARBON_SEMANTICS_BUILTIN_KIND(TypeType, TypeType, "Type")
+CARBON_SEMANTICS_BUILTIN_KIND(TypeType, "Type")
 
 
 // Used when a SemanticNode has an invalid type, which should then be ignored
 // Used when a SemanticNode has an invalid type, which should then be ignored
 // for future type checking.
 // for future type checking.
-// This has a deliberately self-referential type.
-CARBON_SEMANTICS_BUILTIN_KIND(InvalidType, InvalidType, "<unknown>")
+CARBON_SEMANTICS_BUILTIN_KIND(InvalidType, "<unknown>")
 
 
 // -----------------------------------------------------------------------------
 // -----------------------------------------------------------------------------
 // TODO: Below types are all placeholders. While the above may last, the below
 // TODO: Below types are all placeholders. While the above may last, the below
@@ -52,19 +51,16 @@ CARBON_SEMANTICS_BUILTIN_KIND(InvalidType, InvalidType, "<unknown>")
 // -----------------------------------------------------------------------------
 // -----------------------------------------------------------------------------
 
 
 // The type of integer values and integer literals, currently always i32.
 // The type of integer values and integer literals, currently always i32.
-CARBON_SEMANTICS_BUILTIN_KIND(IntegerType, TypeType, "i32")
+CARBON_SEMANTICS_BUILTIN_KIND(IntegerType, "i32")
 
 
 // The type of floating point values and real literals, currently always f64.
 // The type of floating point values and real literals, currently always f64.
-CARBON_SEMANTICS_BUILTIN_KIND(FloatingPointType, TypeType, "f64")
+CARBON_SEMANTICS_BUILTIN_KIND(FloatingPointType, "f64")
 
 
 // The type of string values and String literals.
 // The type of string values and String literals.
-CARBON_SEMANTICS_BUILTIN_KIND(StringType, TypeType, "String")
+CARBON_SEMANTICS_BUILTIN_KIND(StringType, "String")
 
 
 // The canonical empty tuple type.
 // The canonical empty tuple type.
-CARBON_SEMANTICS_BUILTIN_KIND(EmptyTupleType, TypeType, "() as Type")
-
-// The canonical empty tuple.
-CARBON_SEMANTICS_BUILTIN_KIND(EmptyTuple, EmptyTupleType, "()")
+CARBON_SEMANTICS_BUILTIN_KIND(EmptyTupleType, "() as Type")
 
 
 // Keep invalid last, so that we can use values as array indices without needing
 // Keep invalid last, so that we can use values as array indices without needing
 // an invalid entry.
 // an invalid entry.

+ 2 - 8
toolchain/semantics/semantics_context.cpp

@@ -271,14 +271,8 @@ auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id,
   }
   }
 
 
   if (as_type_id == SemanticsNodeId::BuiltinTypeType) {
   if (as_type_id == SemanticsNodeId::BuiltinTypeType) {
-    // When converting `()` to a type, the result is `() as Type`.
-    // TODO: This might switch to be closer to the struct conversion below.
-    if (value_id == SemanticsNodeId::BuiltinEmptyTuple) {
-      if (output_value_id != nullptr) {
-        *output_value_id = SemanticsNodeId::BuiltinEmptyTupleType;
-      }
-      return ImplicitAsKind::Compatible;
-    }
+    // TODO: When converting `()` to a type, the result is `() as Type`.
+    // Right now there is no tuple value support.
 
 
     // When converting `{}` to a type, the result is `{} as Type`.
     // When converting `{}` to a type, the result is `{} as Type`.
     if (value.kind() == SemanticsNodeKind::StructValue &&
     if (value.kind() == SemanticsNodeKind::StructValue &&

+ 9 - 3
toolchain/semantics/semantics_ir.cpp

@@ -17,9 +17,15 @@ auto SemanticsIR::MakeBuiltinIR() -> SemanticsIR {
   SemanticsIR semantics(/*builtin_ir=*/nullptr);
   SemanticsIR semantics(/*builtin_ir=*/nullptr);
   semantics.nodes_.reserve(SemanticsBuiltinKind::ValidCount);
   semantics.nodes_.reserve(SemanticsBuiltinKind::ValidCount);
 
 
-#define CARBON_SEMANTICS_BUILTIN_KIND(Name, Type, ...)     \
-  semantics.nodes_.push_back(SemanticsNode::Builtin::Make( \
-      SemanticsBuiltinKind::Name, SemanticsNodeId::Builtin##Type));
+  // InvalidType uses a self-referential type so that it's not accidentally
+  // treated as a normal type. Every other builtin is a type, including the
+  // self-referential TypeType.
+#define CARBON_SEMANTICS_BUILTIN_KIND(Name, ...)                      \
+  semantics.nodes_.push_back(SemanticsNode::Builtin::Make(            \
+      SemanticsBuiltinKind::Name,                                     \
+      SemanticsBuiltinKind::Name == SemanticsBuiltinKind::InvalidType \
+          ? SemanticsNodeId::BuiltinInvalidType                       \
+          : SemanticsNodeId::BuiltinTypeType));
 #include "toolchain/semantics/semantics_builtin_kind.def"
 #include "toolchain/semantics/semantics_builtin_kind.def"
 
 
   CARBON_CHECK(semantics.node_blocks_.size() == 1)
   CARBON_CHECK(semantics.node_blocks_.size() == 1)