mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:30:12 +01:00
Use a separate type for a parameterized entity name that is waiting for its arguments to arrive. (#1223)
Previously we modeled these as being class types or interface types, with special case checks to treat them as not actually being class or interface types.
This commit is contained in:
@@ -479,6 +479,7 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
|
||||
case Value::Kind::NominalClassType:
|
||||
case Value::Kind::InterfaceType:
|
||||
case Value::Kind::Witness:
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
case Value::Kind::ChoiceType:
|
||||
case Value::Kind::ContinuationType:
|
||||
case Value::Kind::VariableType:
|
||||
@@ -490,6 +491,7 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
|
||||
case Value::Kind::TypeOfClassType:
|
||||
case Value::Kind::TypeOfInterfaceType:
|
||||
case Value::Kind::TypeOfChoiceType:
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
case Value::Kind::StaticArrayType:
|
||||
// TODO: add `CHECK(TypeEqual(type, value->dynamic_type()))`, once we
|
||||
// have Value::dynamic_type.
|
||||
@@ -628,42 +630,37 @@ auto Interpreter::CallFunction(const CallExpression& call,
|
||||
return todo_.Spawn(std::make_unique<StatementAction>(*method.body()),
|
||||
std::move(method_scope));
|
||||
}
|
||||
case Value::Kind::NominalClassType: {
|
||||
const NominalClassType& class_type = cast<NominalClassType>(*fun);
|
||||
const ClassDeclaration& class_decl = class_type.declaration();
|
||||
RuntimeScope type_params_scope(&heap_);
|
||||
BindingMap generic_args;
|
||||
CHECK(class_decl.type_params().has_value())
|
||||
<< "instantiation of non-generic class " << class_type;
|
||||
CHECK(PatternMatch(&(*class_decl.type_params())->value(), arg,
|
||||
call.source_loc(), &type_params_scope, generic_args,
|
||||
trace_stream_));
|
||||
switch (phase()) {
|
||||
case Phase::RunTime:
|
||||
return todo_.FinishAction(arena_->New<NominalClassType>(
|
||||
&class_decl, generic_args, witnesses));
|
||||
case Phase::CompileTime:
|
||||
return todo_.FinishAction(arena_->New<NominalClassType>(
|
||||
&class_decl, generic_args, call.impls()));
|
||||
}
|
||||
}
|
||||
case Value::Kind::InterfaceType: {
|
||||
const InterfaceType& iface_type = cast<InterfaceType>(*fun);
|
||||
const InterfaceDeclaration& iface_decl = iface_type.declaration();
|
||||
case Value::Kind::ParameterizedEntityName: {
|
||||
const auto& name = cast<ParameterizedEntityName>(*fun);
|
||||
const Declaration& decl = name.declaration();
|
||||
RuntimeScope params_scope(&heap_);
|
||||
BindingMap generic_args;
|
||||
CHECK(iface_decl.params().has_value())
|
||||
<< "call of unparameterized interface " << iface_type;
|
||||
CHECK(PatternMatch(&(*iface_decl.params())->value(), arg,
|
||||
call.source_loc(), ¶ms_scope, generic_args,
|
||||
trace_stream_));
|
||||
switch (phase()) {
|
||||
case Phase::RunTime:
|
||||
return todo_.FinishAction(
|
||||
arena_->New<InterfaceType>(&iface_decl, generic_args, witnesses));
|
||||
case Phase::CompileTime:
|
||||
return todo_.FinishAction(arena_->New<InterfaceType>(
|
||||
&iface_decl, generic_args, call.impls()));
|
||||
CHECK(PatternMatch(&name.params().value(), arg, call.source_loc(),
|
||||
¶ms_scope, generic_args, trace_stream_));
|
||||
switch (decl.kind()) {
|
||||
case DeclarationKind::ClassDeclaration: {
|
||||
switch (phase()) {
|
||||
case Phase::RunTime:
|
||||
return todo_.FinishAction(arena_->New<NominalClassType>(
|
||||
&cast<ClassDeclaration>(decl), generic_args, witnesses));
|
||||
case Phase::CompileTime:
|
||||
return todo_.FinishAction(arena_->New<NominalClassType>(
|
||||
&cast<ClassDeclaration>(decl), generic_args, call.impls()));
|
||||
}
|
||||
}
|
||||
case DeclarationKind::InterfaceDeclaration: {
|
||||
switch (phase()) {
|
||||
case Phase::RunTime:
|
||||
return todo_.FinishAction(arena_->New<InterfaceType>(
|
||||
&cast<InterfaceDeclaration>(decl), generic_args, witnesses));
|
||||
case Phase::CompileTime:
|
||||
return todo_.FinishAction(
|
||||
arena_->New<InterfaceType>(&cast<InterfaceDeclaration>(decl),
|
||||
generic_args, call.impls()));
|
||||
}
|
||||
}
|
||||
default:
|
||||
FATAL() << "unknown kind of ParameterizedEntityName " << decl;
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -79,6 +79,7 @@ static auto IsType(Nonnull<const Value*> value) -> bool {
|
||||
case Value::Kind::ContinuationValue:
|
||||
case Value::Kind::StringValue:
|
||||
case Value::Kind::Witness:
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
return false;
|
||||
case Value::Kind::IntType:
|
||||
case Value::Kind::BoolType:
|
||||
@@ -86,6 +87,8 @@ static auto IsType(Nonnull<const Value*> value) -> bool {
|
||||
case Value::Kind::FunctionType:
|
||||
case Value::Kind::PointerType:
|
||||
case Value::Kind::StructType:
|
||||
case Value::Kind::NominalClassType:
|
||||
case Value::Kind::InterfaceType:
|
||||
case Value::Kind::ChoiceType:
|
||||
case Value::Kind::ContinuationType:
|
||||
case Value::Kind::VariableType:
|
||||
@@ -93,6 +96,7 @@ static auto IsType(Nonnull<const Value*> value) -> bool {
|
||||
case Value::Kind::TypeOfClassType:
|
||||
case Value::Kind::TypeOfInterfaceType:
|
||||
case Value::Kind::TypeOfChoiceType:
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
case Value::Kind::StaticArrayType:
|
||||
case Value::Kind::AutoType:
|
||||
return true;
|
||||
@@ -104,10 +108,6 @@ static auto IsType(Nonnull<const Value*> value) -> bool {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Value::Kind::NominalClassType:
|
||||
return !cast<NominalClassType>(*value).IsParameterized();
|
||||
case Value::Kind::InterfaceType:
|
||||
return !cast<InterfaceType>(*value).IsParameterized();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +140,7 @@ static auto IsConcreteType(Nonnull<const Value*> value) -> bool {
|
||||
case Value::Kind::ContinuationValue:
|
||||
case Value::Kind::StringValue:
|
||||
case Value::Kind::Witness:
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
return false;
|
||||
case Value::Kind::IntType:
|
||||
case Value::Kind::BoolType:
|
||||
@@ -147,6 +148,8 @@ static auto IsConcreteType(Nonnull<const Value*> value) -> bool {
|
||||
case Value::Kind::FunctionType:
|
||||
case Value::Kind::PointerType:
|
||||
case Value::Kind::StructType:
|
||||
case Value::Kind::NominalClassType:
|
||||
case Value::Kind::InterfaceType:
|
||||
case Value::Kind::ChoiceType:
|
||||
case Value::Kind::ContinuationType:
|
||||
case Value::Kind::VariableType:
|
||||
@@ -154,6 +157,7 @@ static auto IsConcreteType(Nonnull<const Value*> value) -> bool {
|
||||
case Value::Kind::TypeOfClassType:
|
||||
case Value::Kind::TypeOfInterfaceType:
|
||||
case Value::Kind::TypeOfChoiceType:
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
case Value::Kind::StaticArrayType:
|
||||
return true;
|
||||
case Value::Kind::AutoType:
|
||||
@@ -167,10 +171,6 @@ static auto IsConcreteType(Nonnull<const Value*> value) -> bool {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Value::Kind::NominalClassType:
|
||||
return !cast<NominalClassType>(*value).IsParameterized();
|
||||
case Value::Kind::InterfaceType:
|
||||
return !cast<InterfaceType>(*value).IsParameterized();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,10 +292,8 @@ auto TypeChecker::IsImplicitlyConvertible(
|
||||
return destination->kind() == Value::Kind::InterfaceType;
|
||||
case Value::Kind::InterfaceType:
|
||||
return destination->kind() == Value::Kind::TypeType;
|
||||
case Value::Kind::TypeOfClassType: {
|
||||
return !cast<TypeOfClassType>(*source).class_type().IsParameterized() &&
|
||||
destination->kind() == Value::Kind::TypeType;
|
||||
}
|
||||
case Value::Kind::TypeOfClassType:
|
||||
return destination->kind() == Value::Kind::TypeType;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -452,9 +450,11 @@ auto TypeChecker::ArgumentDeduction(
|
||||
case Value::Kind::TypeOfClassType:
|
||||
case Value::Kind::TypeOfInterfaceType:
|
||||
case Value::Kind::TypeOfChoiceType:
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
return ExpectType(source_loc, "argument deduction", param_type, arg_type);
|
||||
// The rest of these cases should never happen.
|
||||
case Value::Kind::Witness:
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
case Value::Kind::IntValue:
|
||||
case Value::Kind::BoolValue:
|
||||
case Value::Kind::FunctionValue:
|
||||
@@ -551,9 +551,11 @@ auto TypeChecker::Substitute(
|
||||
case Value::Kind::TypeOfClassType:
|
||||
case Value::Kind::TypeOfInterfaceType:
|
||||
case Value::Kind::TypeOfChoiceType:
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
return type;
|
||||
// The rest of these cases should never happen.
|
||||
case Value::Kind::Witness:
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
case Value::Kind::IntValue:
|
||||
case Value::Kind::BoolValue:
|
||||
case Value::Kind::FunctionValue:
|
||||
@@ -1056,36 +1058,26 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
call.set_value_category(ValueCategory::Let);
|
||||
return Success();
|
||||
}
|
||||
case Value::Kind::TypeOfClassType: {
|
||||
// This case handles the application of a generic class to
|
||||
// a type argument, such as Point(i32).
|
||||
const NominalClassType& class_type =
|
||||
cast<TypeOfClassType>(call.function().static_type()).class_type();
|
||||
const ClassDeclaration& class_decl = class_type.declaration();
|
||||
case Value::Kind::TypeOfParameterizedEntityName: {
|
||||
// This case handles the application of a parameterized class or
|
||||
// interface to a set of arguments, such as Point(i32) or
|
||||
// AddWith(i32).
|
||||
const ParameterizedEntityName& param_name =
|
||||
cast<TypeOfParameterizedEntityName>(call.function().static_type())
|
||||
.name();
|
||||
BindingMap generic_args;
|
||||
if (class_type.IsParameterized()) {
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "pattern matching type params and args\n";
|
||||
}
|
||||
RETURN_IF_ERROR(
|
||||
ExpectType(call.source_loc(), "call",
|
||||
&(*class_decl.type_params())->static_type(),
|
||||
&call.argument().static_type()));
|
||||
ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> arg,
|
||||
InterpExp(&call.argument(), arena_, trace_stream_));
|
||||
CHECK(PatternMatch(&(*class_decl.type_params())->value(), arg,
|
||||
call.source_loc(), std::nullopt, generic_args,
|
||||
trace_stream_));
|
||||
} else if (!class_type.type_args().empty()) {
|
||||
return CompilationError(call.source_loc())
|
||||
<< "attempt to instantiate an already instantiated "
|
||||
<< "generic class: " << *e;
|
||||
} else {
|
||||
return CompilationError(call.source_loc())
|
||||
<< "attempt to instantiate a non-generic class: " << *e;
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "pattern matching type params and args\n";
|
||||
}
|
||||
// Find impls for all the impl bindings of the class.
|
||||
RETURN_IF_ERROR(ExpectType(call.source_loc(), "call",
|
||||
¶m_name.params().static_type(),
|
||||
&call.argument().static_type()));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> arg,
|
||||
InterpExp(&call.argument(), arena_, trace_stream_));
|
||||
CHECK(PatternMatch(¶m_name.params().value(), arg,
|
||||
call.source_loc(), std::nullopt, generic_args,
|
||||
trace_stream_));
|
||||
// Find impls for all the impl bindings.
|
||||
ImplExpMap impls;
|
||||
for (const auto& [binding, val] : generic_args) {
|
||||
if (binding->impl_binding().has_value()) {
|
||||
@@ -1098,64 +1090,30 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
impls.emplace(impl_binding, impl);
|
||||
}
|
||||
}
|
||||
Nonnull<NominalClassType*> inst_class_type =
|
||||
arena_->New<NominalClassType>(&class_decl, generic_args, impls);
|
||||
call.set_impls(impls);
|
||||
call.set_static_type(arena_->New<TypeOfClassType>(inst_class_type));
|
||||
call.set_value_category(ValueCategory::Let);
|
||||
return Success();
|
||||
}
|
||||
case Value::Kind::TypeOfInterfaceType: {
|
||||
// This case handles the application of a parameterized class to
|
||||
// its arguments, such as OrderedWith(i32).
|
||||
// FIXME: This is very repetitive with the corresponding case for
|
||||
// parameterized classes.
|
||||
const InterfaceType& iface_type =
|
||||
cast<TypeOfInterfaceType>(call.function().static_type())
|
||||
.interface_type();
|
||||
const InterfaceDeclaration& iface_decl = iface_type.declaration();
|
||||
BindingMap generic_args;
|
||||
if (iface_type.IsParameterized()) {
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "pattern matching interface params and args\n";
|
||||
|
||||
const Declaration& decl = param_name.declaration();
|
||||
switch (decl.kind()) {
|
||||
case DeclarationKind::ClassDeclaration: {
|
||||
Nonnull<NominalClassType*> inst_class_type =
|
||||
arena_->New<NominalClassType>(&cast<ClassDeclaration>(decl),
|
||||
generic_args, impls);
|
||||
call.set_static_type(
|
||||
arena_->New<TypeOfClassType>(inst_class_type));
|
||||
break;
|
||||
}
|
||||
RETURN_IF_ERROR(ExpectType(call.source_loc(), "call",
|
||||
&(*iface_decl.params())->static_type(),
|
||||
&call.argument().static_type()));
|
||||
ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> arg,
|
||||
InterpExp(&call.argument(), arena_, trace_stream_));
|
||||
CHECK(PatternMatch(&(*iface_decl.params())->value(), arg,
|
||||
call.source_loc(), std::nullopt, generic_args,
|
||||
trace_stream_));
|
||||
} else if (!iface_type.args().empty()) {
|
||||
return CompilationError(call.source_loc())
|
||||
<< "attempt to provide arguments to parameterized interface "
|
||||
<< "twice: " << *e;
|
||||
} else {
|
||||
return CompilationError(call.source_loc())
|
||||
<< "attempt to provide arguments to non-parameterized "
|
||||
<< "interface: " << *e;
|
||||
}
|
||||
// Find impls for all the impl bindings of the interface.
|
||||
ImplExpMap impls;
|
||||
for (const auto& [binding, val] : generic_args) {
|
||||
if (binding->impl_binding().has_value()) {
|
||||
Nonnull<const ImplBinding*> impl_binding =
|
||||
*binding->impl_binding();
|
||||
ASSIGN_OR_RETURN(Nonnull<Expression*> impl,
|
||||
impl_scope.Resolve(impl_binding->interface(),
|
||||
generic_args[binding],
|
||||
call.source_loc(), *this));
|
||||
impls.emplace(impl_binding, impl);
|
||||
case DeclarationKind::InterfaceDeclaration: {
|
||||
Nonnull<InterfaceType*> inst_iface_type =
|
||||
arena_->New<InterfaceType>(&cast<InterfaceDeclaration>(decl),
|
||||
generic_args, impls);
|
||||
call.set_static_type(
|
||||
arena_->New<TypeOfInterfaceType>(inst_iface_type));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FATAL() << "unknown type of ParameterizedEntityName for " << decl;
|
||||
}
|
||||
Nonnull<InterfaceType*> inst_iface_type =
|
||||
arena_->New<InterfaceType>(&iface_decl, generic_args, impls);
|
||||
call.set_impls(impls);
|
||||
call.set_static_type(
|
||||
arena_->New<TypeOfInterfaceType>(inst_iface_type));
|
||||
call.set_value_category(ValueCategory::Let);
|
||||
return Success();
|
||||
}
|
||||
default: {
|
||||
@@ -1808,10 +1766,12 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
|
||||
**trace_stream_ << class_scope;
|
||||
}
|
||||
|
||||
Nonnull<NominalClassType*> class_type =
|
||||
arena_->New<NominalClassType>(class_decl);
|
||||
SetConstantValue(class_decl, class_type);
|
||||
class_decl->set_static_type(arena_->New<TypeOfClassType>(class_type));
|
||||
Nonnull<ParameterizedEntityName*> param_name =
|
||||
arena_->New<ParameterizedEntityName>(class_decl,
|
||||
*class_decl->type_params());
|
||||
SetConstantValue(class_decl, param_name);
|
||||
class_decl->set_static_type(
|
||||
arena_->New<TypeOfParameterizedEntityName>(param_name));
|
||||
|
||||
for (Nonnull<Declaration*> m : class_decl->members()) {
|
||||
RETURN_IF_ERROR(DeclareDeclaration(m, class_scope));
|
||||
@@ -1875,11 +1835,17 @@ auto TypeChecker::DeclareInterfaceDeclaration(
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << iface_scope;
|
||||
}
|
||||
}
|
||||
|
||||
Nonnull<InterfaceType*> iface_type = arena_->New<InterfaceType>(iface_decl);
|
||||
SetConstantValue(iface_decl, iface_type);
|
||||
iface_decl->set_static_type(arena_->New<TypeOfInterfaceType>(iface_type));
|
||||
Nonnull<ParameterizedEntityName*> param_name =
|
||||
arena_->New<ParameterizedEntityName>(iface_decl, *iface_decl->params());
|
||||
SetConstantValue(iface_decl, param_name);
|
||||
iface_decl->set_static_type(
|
||||
arena_->New<TypeOfParameterizedEntityName>(param_name));
|
||||
} else {
|
||||
Nonnull<InterfaceType*> iface_type = arena_->New<InterfaceType>(iface_decl);
|
||||
SetConstantValue(iface_decl, iface_type);
|
||||
iface_decl->set_static_type(arena_->New<TypeOfInterfaceType>(iface_type));
|
||||
}
|
||||
|
||||
// Process the Self parameter.
|
||||
RETURN_IF_ERROR(TypeCheckPattern(iface_decl->self(), std::nullopt,
|
||||
@@ -1934,10 +1900,6 @@ auto TypeChecker::DeclareImplDeclaration(Nonnull<ImplDeclaration*> impl_decl,
|
||||
<< "expected constraint after `as`, found value of type "
|
||||
<< *written_iface_type;
|
||||
}
|
||||
if (iface_type->IsParameterized()) {
|
||||
return CompilationError(impl_decl->interface().source_loc())
|
||||
<< "missing arguments for parameterized interface";
|
||||
}
|
||||
|
||||
const auto& iface_decl = iface_type->declaration();
|
||||
impl_decl->set_interface_type(iface_type);
|
||||
|
||||
@@ -350,6 +350,9 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
<< witness.declaration().interface();
|
||||
break;
|
||||
}
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
out << *GetName(cast<ParameterizedEntityName>(*this).declaration());
|
||||
break;
|
||||
case Value::Kind::ChoiceType:
|
||||
out << "choice " << cast<ChoiceType>(*this).name();
|
||||
break;
|
||||
@@ -383,6 +386,10 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
out << "typeof(" << cast<TypeOfChoiceType>(*this).choice_type().name()
|
||||
<< ")";
|
||||
break;
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
out << "typeof(" << cast<TypeOfParameterizedEntityName>(*this).name()
|
||||
<< ")";
|
||||
break;
|
||||
case Value::Kind::StaticArrayType: {
|
||||
const auto& array_type = cast<StaticArrayType>(*this);
|
||||
out << "[" << array_type.element_type() << "; " << array_type.size()
|
||||
@@ -514,6 +521,10 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2) -> bool {
|
||||
case Value::Kind::TypeOfChoiceType:
|
||||
return TypeEqual(&cast<TypeOfChoiceType>(*t1).choice_type(),
|
||||
&cast<TypeOfChoiceType>(*t2).choice_type());
|
||||
case Value::Kind::TypeOfParameterizedEntityName: {
|
||||
return ValueEqual(&cast<TypeOfParameterizedEntityName>(*t1).name(),
|
||||
&cast<TypeOfParameterizedEntityName>(*t2).name());
|
||||
}
|
||||
case Value::Kind::StaticArrayType: {
|
||||
const auto& array1 = cast<StaticArrayType>(*t1);
|
||||
const auto& array2 = cast<StaticArrayType>(*t2);
|
||||
@@ -533,6 +544,7 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2) -> bool {
|
||||
case Value::Kind::LValue:
|
||||
case Value::Kind::BindingPlaceholderValue:
|
||||
case Value::Kind::ContinuationValue:
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
FATAL() << "TypeEqual used to compare non-type values\n"
|
||||
<< *t1 << "\n"
|
||||
<< *t2;
|
||||
@@ -604,6 +616,15 @@ auto ValueEqual(Nonnull<const Value*> v1, Nonnull<const Value*> v2) -> bool {
|
||||
}
|
||||
case Value::Kind::StringValue:
|
||||
return cast<StringValue>(*v1).value() == cast<StringValue>(*v2).value();
|
||||
case Value::Kind::ParameterizedEntityName: {
|
||||
std::optional<std::string> name1 =
|
||||
GetName(cast<ParameterizedEntityName>(v1)->declaration());
|
||||
std::optional<std::string> name2 =
|
||||
GetName(cast<ParameterizedEntityName>(v2)->declaration());
|
||||
CHECK(name1.has_value() && name2.has_value())
|
||||
<< "parameterized name refers to unnamed declaration";
|
||||
return *name1 == *name2;
|
||||
}
|
||||
case Value::Kind::IntType:
|
||||
case Value::Kind::BoolType:
|
||||
case Value::Kind::TypeType:
|
||||
@@ -621,6 +642,7 @@ auto ValueEqual(Nonnull<const Value*> v1, Nonnull<const Value*> v2) -> bool {
|
||||
case Value::Kind::TypeOfClassType:
|
||||
case Value::Kind::TypeOfInterfaceType:
|
||||
case Value::Kind::TypeOfChoiceType:
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
case Value::Kind::StaticArrayType:
|
||||
return TypeEqual(v1, v2);
|
||||
case Value::Kind::NominalClassValue:
|
||||
|
||||
@@ -57,6 +57,7 @@ class Value {
|
||||
ChoiceType,
|
||||
ContinuationType, // The type of a continuation.
|
||||
VariableType, // e.g., generic type parameters.
|
||||
ParameterizedEntityName,
|
||||
BindingPlaceholderValue,
|
||||
AlternativeConstructorValue,
|
||||
ContinuationValue, // A first-class continuation value.
|
||||
@@ -65,6 +66,7 @@ class Value {
|
||||
TypeOfClassType,
|
||||
TypeOfInterfaceType,
|
||||
TypeOfChoiceType,
|
||||
TypeOfParameterizedEntityName,
|
||||
StaticArrayType,
|
||||
};
|
||||
|
||||
@@ -506,10 +508,12 @@ class StructType : public Value {
|
||||
// TODO: Consider splitting this class into several classes.
|
||||
class NominalClassType : public Value {
|
||||
public:
|
||||
// Construct a non-generic class type or a generic class type that has
|
||||
// not yet been applied to type arguments.
|
||||
// Construct a non-generic class type.
|
||||
explicit NominalClassType(Nonnull<const ClassDeclaration*> declaration)
|
||||
: Value(Kind::NominalClassType), declaration_(declaration) {}
|
||||
: Value(Kind::NominalClassType), declaration_(declaration) {
|
||||
CHECK(!declaration->type_params().has_value())
|
||||
<< "missing arguments for parameterized class type";
|
||||
}
|
||||
|
||||
// Construct a class type that represents the result of applying the
|
||||
// given generic class to the `type_args`.
|
||||
@@ -587,7 +591,10 @@ auto FindMember(const std::string& name,
|
||||
class InterfaceType : public Value {
|
||||
public:
|
||||
explicit InterfaceType(Nonnull<const InterfaceDeclaration*> declaration)
|
||||
: Value(Kind::InterfaceType), declaration_(declaration) {}
|
||||
: Value(Kind::InterfaceType), declaration_(declaration) {
|
||||
CHECK(!declaration->params().has_value())
|
||||
<< "missing arguments for parameterized interface type";
|
||||
}
|
||||
explicit InterfaceType(Nonnull<const InterfaceDeclaration*> declaration,
|
||||
const BindingMap& args)
|
||||
: Value(Kind::InterfaceType), declaration_(declaration), args_(args) {}
|
||||
@@ -617,10 +624,6 @@ class InterfaceType : public Value {
|
||||
auto impls() const -> const ImplExpMap& { return impls_; }
|
||||
auto witnesses() const -> const ImplWitnessMap& { return witnesses_; }
|
||||
|
||||
auto IsParameterized() const -> bool {
|
||||
return declaration_->params().has_value() && args_.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
Nonnull<const InterfaceDeclaration*> declaration_;
|
||||
BindingMap args_;
|
||||
@@ -711,6 +714,29 @@ class VariableType : public Value {
|
||||
Nonnull<const GenericBinding*> binding_;
|
||||
};
|
||||
|
||||
// A name of an entity that has explicit parameters, such as a parameterized
|
||||
// class or interface. When arguments for those parameters are provided in a
|
||||
// call, the result will be a class type or interface type.
|
||||
class ParameterizedEntityName : public Value {
|
||||
public:
|
||||
explicit ParameterizedEntityName(Nonnull<const Declaration*> declaration,
|
||||
Nonnull<const TuplePattern*> params)
|
||||
: Value(Kind::ParameterizedEntityName),
|
||||
declaration_(declaration),
|
||||
params_(params) {}
|
||||
|
||||
static auto classof(const Value* value) -> bool {
|
||||
return value->kind() == Kind::ParameterizedEntityName;
|
||||
}
|
||||
|
||||
auto declaration() const -> const Declaration& { return *declaration_; }
|
||||
auto params() const -> const TuplePattern& { return *params_; }
|
||||
|
||||
private:
|
||||
Nonnull<const Declaration*> declaration_;
|
||||
Nonnull<const TuplePattern*> params_;
|
||||
};
|
||||
|
||||
// A first-class continuation representation of a fragment of the stack.
|
||||
// A continuation value behaves like a pointer to the underlying stack
|
||||
// fragment, which is exposed by `Stack()`.
|
||||
@@ -844,6 +870,25 @@ class TypeOfChoiceType : public Value {
|
||||
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.
|
||||
class TypeOfParameterizedEntityName : public Value {
|
||||
public:
|
||||
explicit TypeOfParameterizedEntityName(
|
||||
Nonnull<const ParameterizedEntityName*> name)
|
||||
: Value(Kind::TypeOfParameterizedEntityName), name_(name) {}
|
||||
|
||||
static auto classof(const Value* value) -> bool {
|
||||
return value->kind() == Kind::TypeOfParameterizedEntityName;
|
||||
}
|
||||
|
||||
auto name() const -> const ParameterizedEntityName& { return *name_; }
|
||||
|
||||
private:
|
||||
Nonnull<const ParameterizedEntityName*> name_;
|
||||
};
|
||||
|
||||
// The type of a statically-sized array.
|
||||
//
|
||||
// Note that values of this type are represented as tuples.
|
||||
|
||||
@@ -19,7 +19,10 @@ class Point {
|
||||
}
|
||||
|
||||
fn Main() -> i32 {
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_instantiate_non_generic.carbon:[[@LINE+1]]: attempt to instantiate a non-generic class: Point(i32)
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_instantiate_non_generic.carbon:[[@LINE+4]]: in call, expected a function
|
||||
// CHECK: Point(i32)
|
||||
// CHECK: not an operator of type typeof(class Point)
|
||||
// CHECK-EMPTY:
|
||||
var p: Point(i32) = Point.Origin();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class Point(T:! Type) {
|
||||
// The return type should be Point(T). Point by itself is not a type.
|
||||
fn Create(x: T, y: T) -> Point {
|
||||
return {.x = x, .y = y};
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_return_type_is_type.carbon:[[@LINE+1]]: Expected a type, but got class Point
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_return_type_is_type.carbon:[[@LINE+1]]: Expected a type, but got Point
|
||||
}
|
||||
|
||||
var x: T;
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
package ExplorerTest api;
|
||||
|
||||
class Point(T:! Type) {
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_two_arg_lists.carbon:[[@LINE+1]]: attempt to instantiate an already instantiated generic class: Point(T)(T)
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_class/fail_two_arg_lists.carbon:[[@LINE+4]]: in call, expected a function
|
||||
// CHECK: Point(T)(T)
|
||||
// CHECK: not an operator of type typeof(class Point(T = T:! Type))
|
||||
// CHECK-EMPTY:
|
||||
fn Origin(zero: T) -> Point(T)(T) {
|
||||
return {.x = zero, .y = zero};
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ package ExplorerTest api;
|
||||
interface Vector(Scalar:! Type) {
|
||||
}
|
||||
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_impl_as_parameterized.carbon:[[@LINE+1]]: missing arguments for parameterized interface
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_impl_as_parameterized.carbon:[[@LINE+1]]: expected constraint after `as`, found value of type Vector
|
||||
external impl i32 as Vector {}
|
||||
|
||||
fn Main() -> i32 {
|
||||
|
||||
@@ -92,7 +92,7 @@ class SimpleCheckLine(CheckLine):
|
||||
if self.expected:
|
||||
return f"{self.indent}// CHECK: {self.expected}\n"
|
||||
else:
|
||||
return f"{self.indent}// CHECK-EMPTY\n"
|
||||
return f"{self.indent}// CHECK-EMPTY:\n"
|
||||
|
||||
|
||||
class CheckLineWithLineNumber(CheckLine):
|
||||
|
||||
Reference in New Issue
Block a user