Explorar o código

Remove `TypeOf*Type` for types whose type-of-type can just be `Type` (#2302)

We don't seem to have any need for `TypeOf*Type` types, and having them introduces the temptation to use them during type-checking, which would lead to types having different behavior when their type-of-type is `Type` versus when it's a more precise type. Remove these types for now.

If we later decide that we want each type literal to have a unique type, as we do for value literals, we can introduce a single value kind for that rather than one for each kind of type.

No changes to `TypeOfMemberName`, `TypeOfParameterizedEntityName`, and `TypeOfMixinPseudoType`, which are placeholders, not real types.
Richard Smith %!s(int64=3) %!d(string=hai) anos
pai
achega
561e45033e

+ 2 - 2
explorer/ast/expression.h

@@ -897,12 +897,12 @@ class RewriteWhereClause : public WhereClause {
 //
 // The first operand is rewritten to a generic binding, for example
 // `.Self:! AddableWith(i32)`, which may be used in the clauses.
-class WhereExpression : public Expression {
+class WhereExpression : public RewritableMixin<Expression> {
  public:
   explicit WhereExpression(SourceLocation source_loc,
                            Nonnull<GenericBinding*> self_binding,
                            std::vector<Nonnull<WhereClause*>> clauses)
-      : Expression(AstNodeKind::WhereExpression, source_loc),
+      : RewritableMixin(AstNodeKind::WhereExpression, source_loc),
         self_binding_(self_binding),
         clauses_(std::move(clauses)) {}
 

+ 4 - 9
explorer/interpreter/interpreter.cpp

@@ -228,9 +228,6 @@ auto Interpreter::EvalPrim(Operator op, Nonnull<const Value*> static_type,
       return heap_.Read(cast<PointerValue>(*args[0]).address(), source_loc);
     case Operator::AddressOf:
       return arena_->New<PointerValue>(cast<LValue>(*args[0]).address());
-    case Operator::BitwiseAnd:
-      // If & wasn't rewritten, it's being used to form a constraint.
-      return &cast<TypeOfConstraintType>(static_type)->constraint_type();
     case Operator::As:
     case Operator::Eq:
     case Operator::NotEq:
@@ -238,6 +235,7 @@ auto Interpreter::EvalPrim(Operator op, Nonnull<const Value*> static_type,
     case Operator::LessEq:
     case Operator::Greater:
     case Operator::GreaterEq:
+    case Operator::BitwiseAnd:
     case Operator::BitwiseOr:
     case Operator::BitwiseXor:
     case Operator::BitShiftLeft:
@@ -697,11 +695,7 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
     case Value::Kind::ContinuationValue:
     case Value::Kind::StringType:
     case Value::Kind::StringValue:
-    case Value::Kind::TypeOfClassType:
     case Value::Kind::TypeOfMixinPseudoType:
-    case Value::Kind::TypeOfInterfaceType:
-    case Value::Kind::TypeOfConstraintType:
-    case Value::Kind::TypeOfChoiceType:
     case Value::Kind::TypeOfParameterizedEntityName:
     case Value::Kind::TypeOfMemberName:
     case Value::Kind::StaticArrayType:
@@ -1467,8 +1461,9 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
       break;
     }
     case ExpressionKind::WhereExpression: {
-      return todo_.FinishAction(
-          &cast<TypeOfConstraintType>(exp.static_type()).constraint_type());
+      auto rewrite = cast<WhereExpression>(exp).rewritten_form();
+      CARBON_CHECK(rewrite) << "where expression should be rewritten";
+      return todo_.ReplaceWith(std::make_unique<ExpressionAction>(*rewrite));
     }
     case ExpressionKind::UnimplementedExpression:
       CARBON_FATAL() << "Unimplemented: " << exp;

+ 36 - 101
explorer/interpreter/type_checker.cpp

@@ -127,11 +127,7 @@ static auto IsTypeOfType(Nonnull<const Value*> value) -> bool {
     case Value::Kind::TypeType:
     case Value::Kind::InterfaceType:
     case Value::Kind::ConstraintType:
-    case Value::Kind::TypeOfClassType:
     case Value::Kind::TypeOfMixinPseudoType:
-    case Value::Kind::TypeOfInterfaceType:
-    case Value::Kind::TypeOfConstraintType:
-    case Value::Kind::TypeOfChoiceType:
       // A value of one of these types is itself always a type.
       return true;
   }
@@ -182,10 +178,6 @@ static auto IsType(Nonnull<const Value*> value, bool concrete = false) -> bool {
     case Value::Kind::ContinuationType:
     case Value::Kind::VariableType:
     case Value::Kind::StringType:
-    case Value::Kind::TypeOfClassType:
-    case Value::Kind::TypeOfInterfaceType:
-    case Value::Kind::TypeOfConstraintType:
-    case Value::Kind::TypeOfChoiceType:
     case Value::Kind::StaticArrayType:
       return true;
     case Value::Kind::AutoType:
@@ -267,10 +259,6 @@ static auto ExpectCompleteType(SourceLocation source_loc,
     case Value::Kind::BoolType:
     case Value::Kind::StringType:
     case Value::Kind::PointerType:
-    case Value::Kind::TypeOfClassType:
-    case Value::Kind::TypeOfInterfaceType:
-    case Value::Kind::TypeOfConstraintType:
-    case Value::Kind::TypeOfChoiceType:
     case Value::Kind::TypeType:
     case Value::Kind::FunctionType:
     case Value::Kind::StructType:
@@ -503,10 +491,6 @@ auto TypeChecker::IsImplicitlyConvertible(
       break;
     case Value::Kind::InterfaceType:
     case Value::Kind::ConstraintType:
-    case Value::Kind::TypeOfClassType:
-    case Value::Kind::TypeOfChoiceType:
-    case Value::Kind::TypeOfInterfaceType:
-    case Value::Kind::TypeOfConstraintType:
       // TODO: These types should presumably also convert to constraint types.
       if (isa<TypeType>(destination)) {
         return true;
@@ -609,8 +593,7 @@ auto TypeChecker::BuildBuiltinMethodCall(const ImplScope& impl_scope,
 
   // Build an expression to perform the call `source.(interface.method)(args)`.
   Nonnull<Expression*> iface_expr = arena_->New<ValueLiteral>(
-      source_loc, iface_type, arena_->New<TypeOfInterfaceType>(iface_type),
-      ValueCategory::Let);
+      source_loc, iface_type, arena_->New<TypeType>(), ValueCategory::Let);
   Nonnull<Expression*> iface_member = arena_->New<SimpleMemberAccessExpression>(
       source_loc, iface_expr, method.name);
   Nonnull<Expression*> method_access =
@@ -916,10 +899,6 @@ auto TypeChecker::ArgumentDeduction::Deduce(Nonnull<const Value*> param,
     case Value::Kind::BoolType:
     case Value::Kind::TypeType:
     case Value::Kind::StringType:
-    case Value::Kind::TypeOfClassType:
-    case Value::Kind::TypeOfInterfaceType:
-    case Value::Kind::TypeOfConstraintType:
-    case Value::Kind::TypeOfChoiceType:
     case Value::Kind::TypeOfParameterizedEntityName:
     case Value::Kind::TypeOfMemberName: {
       return handle_non_deduced_type();
@@ -1626,11 +1605,7 @@ auto TypeChecker::Substitute(const Bindings& bindings,
     case Value::Kind::StringType:
     case Value::Kind::MixinPseudoType:
       return type;
-    case Value::Kind::TypeOfClassType:
     case Value::Kind::TypeOfMixinPseudoType:
-    case Value::Kind::TypeOfInterfaceType:
-    case Value::Kind::TypeOfConstraintType:
-    case Value::Kind::TypeOfChoiceType:
     case Value::Kind::TypeOfParameterizedEntityName:
     case Value::Kind::TypeOfMemberName:
       // TODO: We should substitute into the value and produce a new type of
@@ -2285,11 +2260,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
           }
           return Success();
         }
-        case Value::Kind::TypeType:
-        case Value::Kind::TypeOfChoiceType:
-        case Value::Kind::TypeOfClassType:
-        case Value::Kind::TypeOfConstraintType:
-        case Value::Kind::TypeOfInterfaceType: {
+        case Value::Kind::TypeType: {
           // This is member access into an unconstrained type. Evaluate it and
           // perform lookup in the result.
           CARBON_ASSIGN_OR_RETURN(
@@ -2657,31 +2628,27 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
           // `&` between type-of-types performs constraint combination.
           // TODO: Should this be done via an intrinsic?
           if (IsTypeOfType(ts[0]) && IsTypeOfType(ts[1])) {
-            std::optional<Nonnull<const ConstraintType*>> constraints[2];
-            for (int i : {0, 1}) {
-              // TODO: This should be done based on the values, not their
-              // types.
-              if (auto* iface_type_type =
-                      dyn_cast<TypeOfInterfaceType>(ts[i])) {
-                CARBON_ASSIGN_OR_RETURN(
-                    constraints[i],
-                    MakeConstraintForInterface(
-                        e->source_loc(), &iface_type_type->interface_type()));
-              } else if (auto* constraint_type_type =
-                             dyn_cast<TypeOfConstraintType>(ts[i])) {
-                constraints[i] = &constraint_type_type->constraint_type();
-              } else {
-                return ProgramError(op.arguments()[i]->source_loc())
-                       << "argument to " << ToString(op.op())
-                       << " should be a constraint, found `" << *ts[i] << "`";
-              }
-            }
+            CARBON_ASSIGN_OR_RETURN(
+                Nonnull<const Value*> lhs,
+                InterpExp(op.arguments()[0], arena_, trace_stream_));
+            CARBON_ASSIGN_OR_RETURN(
+                Nonnull<const Value*> rhs,
+                InterpExp(op.arguments()[1], arena_, trace_stream_));
+            CARBON_ASSIGN_OR_RETURN(
+                Nonnull<const ConstraintType*> lhs_constraint,
+                ConvertToConstraintType(op.arguments()[0]->source_loc(),
+                                        "first operand of `&`", lhs));
+            CARBON_ASSIGN_OR_RETURN(
+                Nonnull<const ConstraintType*> rhs_constraint,
+                ConvertToConstraintType(op.arguments()[1]->source_loc(),
+                                        "second operand of `&`", rhs));
             CARBON_ASSIGN_OR_RETURN(
                 Nonnull<const ConstraintType*> result,
                 CombineConstraints(e->source_loc(),
-                                   {*constraints[0], *constraints[1]}));
-            op.set_static_type(arena_->New<TypeOfConstraintType>(result));
-            op.set_value_category(ValueCategory::Let);
+                                   {lhs_constraint, rhs_constraint}));
+            op.set_rewritten_form(arena_->New<ValueLiteral>(
+                op.source_loc(), result, arena_->New<TypeType>(),
+                ValueCategory::Let));
             return Success();
           }
           return handle_binary_operator(Builtins::BitAndWith);
@@ -2831,44 +2798,17 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
           CARBON_RETURN_IF_ERROR(DeduceCallBindings(
               call, &param_name.params().static_type(), generic_parameters,
               /*deduced_bindings=*/llvm::None, impl_bindings, impl_scope));
-          Nonnull<const Bindings*> bindings = &call.bindings();
-
-          const Declaration& decl = param_name.declaration();
-          switch (decl.kind()) {
-            case DeclarationKind::ClassDeclaration: {
-              Nonnull<NominalClassType*> inst_class_type =
-                  arena_->New<NominalClassType>(&cast<ClassDeclaration>(decl),
-                                                bindings);
-              call.set_static_type(
-                  arena_->New<TypeOfClassType>(inst_class_type));
-              call.set_value_category(ValueCategory::Let);
-              break;
-            }
-            case DeclarationKind::InterfaceDeclaration: {
-              Nonnull<InterfaceType*> inst_iface_type =
-                  arena_->New<InterfaceType>(&cast<InterfaceDeclaration>(decl),
-                                             bindings);
-              call.set_static_type(
-                  arena_->New<TypeOfInterfaceType>(inst_iface_type));
-              call.set_value_category(ValueCategory::Let);
-              break;
-            }
-            case DeclarationKind::ChoiceDeclaration: {
-              Nonnull<ChoiceType*> ct = arena_->New<ChoiceType>(
-                  cast<ChoiceDeclaration>(&decl), bindings);
-              Nonnull<TypeOfChoiceType*> inst_choice_type =
-                  arena_->New<TypeOfChoiceType>(ct);
-              call.set_static_type(inst_choice_type);
-              call.set_value_category(ValueCategory::Let);
-              break;
-            }
-            default:
-              CARBON_FATAL()
-                  << "unknown type of ParameterizedEntityName for " << decl;
-          }
+
+          // Currently the only kinds of parameterized entities we support are
+          // types.
+          CARBON_CHECK(
+              isa<ClassDeclaration, InterfaceDeclaration, ChoiceDeclaration>(
+                  param_name.declaration()))
+              << "unknown type of ParameterizedEntityName for " << param_name;
+          call.set_static_type(arena_->New<TypeType>());
+          call.set_value_category(ValueCategory::Let);
           return Success();
         }
-        case Value::Kind::TypeOfChoiceType:
         default: {
           return ProgramError(e->source_loc())
                  << "in call `" << *e
@@ -3209,9 +3149,9 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
         }
       }
 
-      where.set_static_type(
-          arena_->New<TypeOfConstraintType>(std::move(builder).Build(arena_)));
-      where.set_value_category(ValueCategory::Let);
+      where.set_rewritten_form(arena_->New<ValueLiteral>(
+          where.source_loc(), std::move(builder).Build(arena_),
+          arena_->New<TypeType>(), ValueCategory::Let));
       return Success();
     }
     case ExpressionKind::UnimplementedExpression:
@@ -3309,8 +3249,7 @@ auto TypeChecker::TypeCheckWhereClause(Nonnull<WhereClause*> clause,
       auto& is_clause = cast<IsWhereClause>(*clause);
       CARBON_RETURN_IF_ERROR(TypeCheckTypeExp(&is_clause.type(), impl_scope));
       CARBON_RETURN_IF_ERROR(TypeCheckExp(&is_clause.constraint(), impl_scope));
-      if (!isa<TypeOfInterfaceType, TypeOfConstraintType, TypeType>(
-              is_clause.constraint().static_type())) {
+      if (!isa<TypeType>(is_clause.constraint().static_type())) {
         return ProgramError(is_clause.constraint().source_loc())
                << "expression after `is` does not resolve to a constraint, "
                << "found " << is_clause.constraint().static_type();
@@ -4036,7 +3975,7 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
   // should have the value `MyType(T, U)`.
   Nonnull<NominalClassType*> self_type = arena_->New<NominalClassType>(
       class_decl, Bindings::SymbolicIdentity(arena_, bindings));
-  self->set_static_type(arena_->New<TypeOfClassType>(self_type));
+  self->set_static_type(arena_->New<TypeType>());
   self->set_constant_value(self_type);
 
   // The declarations of the members may refer to the class, so we must set the
@@ -4252,7 +4191,7 @@ auto TypeChecker::DeclareInterfaceDeclaration(
         iface_decl, Bindings::SymbolicIdentity(arena_, bindings));
   } else {
     iface_type = arena_->New<InterfaceType>(iface_decl);
-    iface_decl->set_static_type(arena_->New<TypeOfInterfaceType>(iface_type));
+    iface_decl->set_static_type(arena_->New<TypeType>());
     iface_decl->set_constant_value(iface_type);
   }
 
@@ -4712,7 +4651,7 @@ auto TypeChecker::DeclareChoiceDeclaration(Nonnull<ChoiceDeclaration*> choice,
   auto ct = arena_->New<ChoiceType>(
       choice, Bindings::SymbolicIdentity(arena_, bindings));
 
-  choice->set_static_type(arena_->New<TypeOfChoiceType>(ct));
+  choice->set_static_type(arena_->New<TypeType>());
   choice->set_constant_value(ct);
   return Success();
 }
@@ -4773,10 +4712,6 @@ static bool IsValidTypeForAliasTarget(Nonnull<const Value*> type) {
     case Value::Kind::InterfaceType:
     case Value::Kind::ConstraintType:
     case Value::Kind::TypeType:
-    case Value::Kind::TypeOfClassType:
-    case Value::Kind::TypeOfInterfaceType:
-    case Value::Kind::TypeOfConstraintType:
-    case Value::Kind::TypeOfChoiceType:
     case Value::Kind::TypeOfParameterizedEntityName:
     case Value::Kind::TypeOfMemberName:
       return true;

+ 0 - 38
explorer/interpreter/value.cpp

@@ -530,9 +530,6 @@ void Value::Print(llvm::raw_ostream& out) const {
       out.write_escaped(cast<StringValue>(*this).value());
       out << "\"";
       break;
-    case Value::Kind::TypeOfClassType:
-      out << "typeof(" << cast<TypeOfClassType>(*this).class_type() << ")";
-      break;
     case Value::Kind::TypeOfMixinPseudoType:
       out << "typeof("
           << cast<TypeOfMixinPseudoType>(*this)
@@ -541,22 +538,6 @@ void Value::Print(llvm::raw_ostream& out) const {
                  .name()
           << ")";
       break;
-    case Value::Kind::TypeOfInterfaceType:
-      out << "typeof("
-          << cast<TypeOfInterfaceType>(*this)
-                 .interface_type()
-                 .declaration()
-                 .name()
-          << ")";
-      break;
-    case Value::Kind::TypeOfConstraintType:
-      out << "typeof(" << cast<TypeOfConstraintType>(*this).constraint_type()
-          << ")";
-      break;
-    case Value::Kind::TypeOfChoiceType:
-      out << "typeof(" << cast<TypeOfChoiceType>(*this).choice_type().name()
-          << ")";
-      break;
     case Value::Kind::TypeOfParameterizedEntityName:
       out << "parameterized entity name "
           << cast<TypeOfParameterizedEntityName>(*this).name();
@@ -743,21 +724,6 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2,
     case Value::Kind::VariableType:
       return &cast<VariableType>(*t1).binding() ==
              &cast<VariableType>(*t2).binding();
-    case Value::Kind::TypeOfClassType:
-      return TypeEqual(&cast<TypeOfClassType>(*t1).class_type(),
-                       &cast<TypeOfClassType>(*t2).class_type(), equality_ctx);
-    case Value::Kind::TypeOfInterfaceType:
-      return TypeEqual(&cast<TypeOfInterfaceType>(*t1).interface_type(),
-                       &cast<TypeOfInterfaceType>(*t2).interface_type(),
-                       equality_ctx);
-    case Value::Kind::TypeOfConstraintType:
-      return TypeEqual(&cast<TypeOfConstraintType>(*t1).constraint_type(),
-                       &cast<TypeOfConstraintType>(*t2).constraint_type(),
-                       equality_ctx);
-    case Value::Kind::TypeOfChoiceType:
-      return TypeEqual(&cast<TypeOfChoiceType>(*t1).choice_type(),
-                       &cast<TypeOfChoiceType>(*t2).choice_type(),
-                       equality_ctx);
     case Value::Kind::StaticArrayType: {
       const auto& array1 = cast<StaticArrayType>(*t1);
       const auto& array2 = cast<StaticArrayType>(*t2);
@@ -904,11 +870,7 @@ auto ValueStructurallyEqual(
     case Value::Kind::ContinuationType:
     case Value::Kind::VariableType:
     case Value::Kind::StringType:
-    case Value::Kind::TypeOfClassType:
     case Value::Kind::TypeOfMixinPseudoType:
-    case Value::Kind::TypeOfInterfaceType:
-    case Value::Kind::TypeOfConstraintType:
-    case Value::Kind::TypeOfChoiceType:
     case Value::Kind::TypeOfParameterizedEntityName:
     case Value::Kind::TypeOfMemberName:
     case Value::Kind::StaticArrayType:

+ 1 - 78
explorer/interpreter/value.h

@@ -76,11 +76,7 @@ class Value {
     ContinuationValue,  // A first-class continuation value.
     StringType,
     StringValue,
-    TypeOfClassType,
     TypeOfMixinPseudoType,
-    TypeOfInterfaceType,
-    TypeOfConstraintType,
-    TypeOfChoiceType,
     TypeOfParameterizedEntityName,
     TypeOfMemberName,
     StaticArrayType,
@@ -640,10 +636,7 @@ class NominalClassType : public Value {
 
   auto type_args() const -> const BindingMap& { return bindings_->args(); }
 
-  // Witnesses for each of the class's impl bindings. These will not in general
-  // be set for class types that are only intended to be used within
-  // type-checking and not at runtime, such as in the static_type() of an
-  // expression or the type in a TypeOfClassType.
+  // Witnesses for each of the class's impl bindings.
   auto witnesses() const -> const ImplWitnessMap& {
     return bindings_->witnesses();
   }
@@ -1218,25 +1211,6 @@ class StringValue : public Value {
   std::string value_;
 };
 
-// The type of an expression whose value is a class type. Currently there is no
-// way to explicitly name such a type in Carbon code, but we are tentatively
-// using `typeof(ClassName)` as the debug-printing format, in anticipation of
-// something like that becoming valid Carbon syntax.
-class TypeOfClassType : public Value {
- public:
-  explicit TypeOfClassType(Nonnull<const NominalClassType*> class_type)
-      : Value(Kind::TypeOfClassType), class_type_(class_type) {}
-
-  static auto classof(const Value* value) -> bool {
-    return value->kind() == Kind::TypeOfClassType;
-  }
-
-  auto class_type() const -> const NominalClassType& { return *class_type_; }
-
- private:
-  Nonnull<const NominalClassType*> class_type_;
-};
-
 class TypeOfMixinPseudoType : public Value {
  public:
   explicit TypeOfMixinPseudoType(Nonnull<const MixinPseudoType*> class_type)
@@ -1252,57 +1226,6 @@ class TypeOfMixinPseudoType : public Value {
   Nonnull<const MixinPseudoType*> mixin_type_;
 };
 
-class TypeOfInterfaceType : public Value {
- public:
-  explicit TypeOfInterfaceType(Nonnull<const InterfaceType*> iface_type)
-      : Value(Kind::TypeOfInterfaceType), iface_type_(iface_type) {}
-
-  static auto classof(const Value* value) -> bool {
-    return value->kind() == Kind::TypeOfInterfaceType;
-  }
-
-  auto interface_type() const -> const InterfaceType& { return *iface_type_; }
-
- private:
-  Nonnull<const InterfaceType*> iface_type_;
-};
-
-class TypeOfConstraintType : public Value {
- public:
-  explicit TypeOfConstraintType(Nonnull<const ConstraintType*> constraint_type)
-      : Value(Kind::TypeOfConstraintType), constraint_type_(constraint_type) {}
-
-  static auto classof(const Value* value) -> bool {
-    return value->kind() == Kind::TypeOfConstraintType;
-  }
-
-  auto constraint_type() const -> const ConstraintType& {
-    return *constraint_type_;
-  }
-
- private:
-  Nonnull<const ConstraintType*> constraint_type_;
-};
-
-// The type of an expression whose value is a choice type. Currently there is no
-// way to explicitly name such a type in Carbon code, but we are tentatively
-// using `typeof(ChoiceName)` as the debug-printing format, in anticipation of
-// something like that becoming valid Carbon syntax.
-class TypeOfChoiceType : public Value {
- public:
-  explicit TypeOfChoiceType(Nonnull<const ChoiceType*> choice_type)
-      : Value(Kind::TypeOfChoiceType), choice_type_(choice_type) {}
-
-  static auto classof(const Value* value) -> bool {
-    return value->kind() == Kind::TypeOfChoiceType;
-  }
-
-  auto choice_type() const -> const ChoiceType& { return *choice_type_; }
-
- private:
-  Nonnull<const ChoiceType*> choice_type_;
-};
-
 // The type of an expression whose value is the name of a parameterized entity.
 // Such an expression can only be used as the operand of a call expression that
 // provides arguments for the parameters.

+ 19 - 0
explorer/testdata/choice/type_of_type.carbon

@@ -0,0 +1,19 @@
+// 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: %{explorer-run}
+// RUN: %{explorer-run-trace}
+// CHECK:STDOUT: result: 0
+
+package ExplorerTest api;
+
+choice C {}
+
+fn Main() -> i32 {
+  var a: auto = C;
+  // OK: Type of `C` is `Type`.
+  a = i32;
+  return 0;
+}

+ 2 - 2
explorer/testdata/class/empty_class.carbon

@@ -12,8 +12,8 @@ package ExplorerTest api;
 class A { fn F[me: Self]() -> i32 { return 0; } }
 
 fn Main() -> i32 {
-  // {} is a bit strange; its type is {}. Make sure we can properly convert a
-  // value of type {} to type TypeOfClassType.
+  // {} is a bit strange: its type is {}. Make sure we can properly convert a
+  // value of type {} to class type.
   var a: A = {};
   return a.F();
 }

+ 19 - 0
explorer/testdata/class/type_of_type.carbon

@@ -0,0 +1,19 @@
+// 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: %{explorer-run}
+// RUN: %{explorer-run-trace}
+// CHECK:STDOUT: result: 0
+
+package ExplorerTest api;
+
+class C {}
+
+fn Main() -> i32 {
+  var a: auto = C;
+  // OK: Type of `C` is `Type`.
+  a = i32;
+  return 0;
+}

+ 19 - 0
explorer/testdata/constraint/type_of_type.carbon

@@ -0,0 +1,19 @@
+// 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: %{explorer-run}
+// RUN: %{explorer-run-trace}
+// CHECK:STDOUT: result: 0
+
+package ExplorerTest api;
+
+interface I {}
+
+fn Main() -> i32 {
+  var a: auto = I where .Self == i32;
+  // OK: Type of `I where ...` is `Type`.
+  a = i32;
+  return 0;
+}

+ 1 - 1
explorer/testdata/generic_class/fail_instantiate_non_generic.carbon

@@ -17,7 +17,7 @@ class Point {
 }
 
 fn Main() -> i32 {
-  // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_instantiate_non_generic.carbon:[[@LINE+1]]: in call `Point(i32)`, expected callee to be a function, found `typeof(class Point)`
+  // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_instantiate_non_generic.carbon:[[@LINE+1]]: in call `Point(i32)`, expected callee to be a function, found `Type`
   var p: Point(i32) = Point.Origin();
   return 0;
 }

+ 1 - 1
explorer/testdata/generic_class/fail_self_with_arg.carbon

@@ -11,7 +11,7 @@ package ExplorerTest api;
 class Point(T:! Type) {
 
   // Error: wrote `Self(T)` instead of `Self`.
-  // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_self_with_arg.carbon:[[@LINE+1]]: in call `Self(T)`, expected callee to be a function, found `typeof(class Point(T = T))`
+  // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_self_with_arg.carbon:[[@LINE+1]]: in call `Self(T)`, expected callee to be a function, found `Type`
   fn Origin(zero: T) -> Self(T) {
     return {.x = zero, .y = zero};
   }

+ 1 - 1
explorer/testdata/generic_class/fail_two_arg_lists.carbon

@@ -9,7 +9,7 @@
 package ExplorerTest api;
 
 class Point(T:! Type) {
-  // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_two_arg_lists.carbon:[[@LINE+1]]: in call `Point(T)(T)`, expected callee to be a function, found `typeof(class Point(T = T))`
+  // CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_two_arg_lists.carbon:[[@LINE+1]]: in call `Point(T)(T)`, expected callee to be a function, found `Type`
   fn Origin(zero: T) -> Point(T)(T) {
     return {.x = zero, .y = zero};
   }

+ 19 - 0
explorer/testdata/interface/type_of_type.carbon

@@ -0,0 +1,19 @@
+// 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: %{explorer-run}
+// RUN: %{explorer-run-trace}
+// CHECK:STDOUT: result: 0
+
+package ExplorerTest api;
+
+interface I {}
+
+fn Main() -> i32 {
+  var a: auto = I;
+  // OK: Type of `I` is `Type`.
+  a = i32;
+  return 0;
+}

+ 17 - 0
explorer/testdata/operators/combine.carbon

@@ -0,0 +1,17 @@
+// 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: %{explorer-run}
+// RUN: %{explorer-run-trace}
+// CHECK:STDOUT: result: 0
+
+package ExplorerTest api;
+
+fn F[T:! Type & Type](x: T) {}
+
+fn Main() -> i32 {
+  F(0);
+  return 0;
+}

+ 16 - 0
explorer/testdata/operators/fail_combine_lhs.carbon

@@ -0,0 +1,16 @@
+// 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} %{explorer-run}
+// RUN: %{not} %{explorer-run-trace}
+
+package ExplorerTest api;
+
+// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/operators/fail_combine_lhs.carbon:[[@LINE+1]]: expected a constraint in first operand of `&`, found i32
+fn F[T:! i32 & Type]();
+
+fn Main() -> i32 {
+  return 0;
+}

+ 18 - 0
explorer/testdata/operators/fail_combine_rhs.carbon

@@ -0,0 +1,18 @@
+// 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} %{explorer-run}
+// RUN: %{not} %{explorer-run-trace}
+
+package ExplorerTest api;
+
+class C {}
+
+// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/operators/fail_combine_rhs.carbon:[[@LINE+1]]: expected a constraint in second operand of `&`, found class C
+fn F[T:! Type & C]();
+
+fn Main() -> i32 {
+  return 0;
+}