Skip to content

Commit

Permalink
Remove TypeOf*Type for types whose type-of-type can just be Type (c…
Browse files Browse the repository at this point in the history
…arbon-language#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.
  • Loading branch information
zygoloid committed Oct 18, 2022
1 parent 1c57704 commit 561e450
Show file tree
Hide file tree
Showing 16 changed files with 175 additions and 233 deletions.
4 changes: 2 additions & 2 deletions explorer/ast/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {}

Expand Down
13 changes: 4 additions & 9 deletions explorer/interpreter/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,16 +228,14 @@ 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:
case Operator::Less:
case Operator::LessEq:
case Operator::Greater:
case Operator::GreaterEq:
case Operator::BitwiseAnd:
case Operator::BitwiseOr:
case Operator::BitwiseXor:
case Operator::BitShiftLeft:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down
137 changes: 36 additions & 101 deletions explorer/interpreter/type_checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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;
Expand Down
38 changes: 0 additions & 38 deletions explorer/interpreter/value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
Loading

0 comments on commit 561e450

Please sign in to comment.