mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Drop support for named tuple fields (#886)
Rationale: Based on the status of #478 and #505, Carbon won't have this feature for a while, and it will be simpler not to support it on spec in the meantime.
This commit is contained in:
@@ -18,18 +18,17 @@ namespace Carbon {
|
||||
static void AddIntrinsics(Nonnull<Arena*> arena,
|
||||
std::vector<Nonnull<Declaration*>>* declarations) {
|
||||
SourceLocation source_loc("<intrinsic>", 0);
|
||||
std::vector<TuplePattern::Field> print_fields = {TuplePattern::Field(
|
||||
"0", arena->New<BindingPattern>(
|
||||
source_loc, "format_str",
|
||||
arena->New<ExpressionPattern>(
|
||||
arena->New<StringTypeLiteral>(source_loc))))};
|
||||
std::vector<Nonnull<Pattern*>> print_params = {arena->New<BindingPattern>(
|
||||
source_loc, "format_str",
|
||||
arena->New<ExpressionPattern>(
|
||||
arena->New<StringTypeLiteral>(source_loc)))};
|
||||
auto print_return = arena->New<Return>(
|
||||
source_loc,
|
||||
arena->New<IntrinsicExpression>(IntrinsicExpression::Intrinsic::Print),
|
||||
false);
|
||||
auto print = arena->New<FunctionDeclaration>(arena->New<FunctionDefinition>(
|
||||
source_loc, "Print", std::vector<GenericBinding>(),
|
||||
arena->New<TuplePattern>(source_loc, print_fields),
|
||||
arena->New<TuplePattern>(source_loc, print_params),
|
||||
arena->New<ExpressionPattern>(arena->New<TupleLiteral>(source_loc)),
|
||||
/*is_omitted_return_type=*/false, print_return));
|
||||
declarations->insert(declarations->begin(), print);
|
||||
|
||||
@@ -201,20 +201,14 @@ auto Interpreter::CreateTuple(Nonnull<Action*> act,
|
||||
// -> { { `(v1,...,vn) :: C, E, F} :: S, H}
|
||||
const auto& tup_lit = cast<TupleLiteral>(*exp);
|
||||
CHECK(act->results().size() == tup_lit.fields().size());
|
||||
std::vector<TupleElement> elements;
|
||||
for (size_t i = 0; i < act->results().size(); ++i) {
|
||||
elements.push_back(
|
||||
{.name = tup_lit.fields()[i].name(), .value = act->results()[i]});
|
||||
}
|
||||
|
||||
return arena->New<TupleValue>(std::move(elements));
|
||||
return arena->New<TupleValue>(act->results());
|
||||
}
|
||||
|
||||
auto Interpreter::CreateStruct(const std::vector<FieldInitializer>& fields,
|
||||
const std::vector<Nonnull<const Value*>>& values)
|
||||
-> Nonnull<const Value*> {
|
||||
CHECK(fields.size() == values.size());
|
||||
std::vector<TupleElement> elements;
|
||||
std::vector<StructElement> elements;
|
||||
for (size_t i = 0; i < fields.size(); ++i) {
|
||||
elements.push_back({.name = fields[i].name(), .value = values[i]});
|
||||
}
|
||||
@@ -247,15 +241,8 @@ auto Interpreter::PatternMatch(Nonnull<const Value*> p, Nonnull<const Value*> v,
|
||||
}
|
||||
Env values(arena);
|
||||
for (size_t i = 0; i < p_tup.Elements().size(); ++i) {
|
||||
if (p_tup.Elements()[i].name != v_tup.Elements()[i].name) {
|
||||
FATAL_PROGRAM_ERROR(source_loc)
|
||||
<< "Tuple field name '" << v_tup.Elements()[i].name
|
||||
<< "' does not match pattern field name '"
|
||||
<< p_tup.Elements()[i].name << "'";
|
||||
}
|
||||
std::optional<Env> matches =
|
||||
PatternMatch(p_tup.Elements()[i].value,
|
||||
v_tup.Elements()[i].value, source_loc);
|
||||
std::optional<Env> matches = PatternMatch(
|
||||
p_tup.Elements()[i], v_tup.Elements()[i], source_loc);
|
||||
if (!matches) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -356,14 +343,9 @@ void Interpreter::PatternAssignment(Nonnull<const Value*> pat,
|
||||
<< "arity mismatch in tuple pattern assignment:\n pattern: "
|
||||
<< pat_tup << "\n value: " << val_tup;
|
||||
}
|
||||
for (const TupleElement& pattern_element : pat_tup.Elements()) {
|
||||
std::optional<Nonnull<const Value*>> value_field =
|
||||
val_tup.FindField(pattern_element.name);
|
||||
if (!value_field) {
|
||||
FATAL_RUNTIME_ERROR(source_loc)
|
||||
<< "field " << pattern_element.name << "not in " << *val;
|
||||
}
|
||||
PatternAssignment(pattern_element.value, *value_field, source_loc);
|
||||
for (size_t i = 0; i < pat_tup.Elements().size(); ++i) {
|
||||
PatternAssignment(pat_tup.Elements()[i], val_tup.Elements()[i],
|
||||
source_loc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -453,7 +435,7 @@ auto Interpreter::StepLvalue() -> Transition {
|
||||
// -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S,
|
||||
// H}
|
||||
return Spawn{arena->New<LValAction>(
|
||||
&cast<TupleLiteral>(*exp).fields()[act->pos()].expression())};
|
||||
cast<TupleLiteral>(*exp).fields()[act->pos()])};
|
||||
} else {
|
||||
return Done{CreateTuple(act, exp)};
|
||||
}
|
||||
@@ -497,19 +479,13 @@ auto Interpreter::StepExp() -> Transition {
|
||||
} else {
|
||||
// { { v :: [][i] :: C, E, F} :: S, H}
|
||||
// -> { { v_i :: C, E, F} : S, H}
|
||||
auto* tuple = dyn_cast<TupleValue>(act->results()[0]);
|
||||
if (tuple == nullptr) {
|
||||
const auto& tuple = cast<TupleValue>(*act->results()[0]);
|
||||
int i = cast<IntValue>(*act->results()[1]).Val();
|
||||
if (i < 0 || i >= static_cast<int>(tuple.Elements().size())) {
|
||||
FATAL_RUNTIME_ERROR_NO_LINE()
|
||||
<< "expected a tuple in field access, not " << *act->results()[0];
|
||||
<< "index " << i << " out of range in " << tuple;
|
||||
}
|
||||
std::string f =
|
||||
std::to_string(cast<IntValue>(*act->results()[1]).Val());
|
||||
std::optional<Nonnull<const Value*>> field = tuple->FindField(f);
|
||||
if (!field) {
|
||||
FATAL_RUNTIME_ERROR_NO_LINE()
|
||||
<< "field " << f << " not in " << *tuple;
|
||||
}
|
||||
return Done{*field};
|
||||
return Done{tuple.Elements()[i]};
|
||||
}
|
||||
}
|
||||
case Expression::Kind::TupleLiteral: {
|
||||
@@ -520,7 +496,7 @@ auto Interpreter::StepExp() -> Transition {
|
||||
// -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S,
|
||||
// H}
|
||||
return Spawn{arena->New<ExpressionAction>(
|
||||
&cast<TupleLiteral>(*exp).fields()[act->pos()].expression())};
|
||||
cast<TupleLiteral>(*exp).fields()[act->pos()])};
|
||||
} else {
|
||||
return Done{CreateTuple(act, exp)};
|
||||
}
|
||||
@@ -603,11 +579,6 @@ auto Interpreter::StepExp() -> Transition {
|
||||
// { { v2 :: v1([]) :: C, E, F} :: S, H}
|
||||
// -> { {C',E',F'} :: {C, E, F} :: S, H}
|
||||
switch (act->results()[0]->kind()) {
|
||||
case Value::Kind::NominalClassType: {
|
||||
Nonnull<const Value*> arg =
|
||||
CopyVal(arena, act->results()[1], exp->source_loc());
|
||||
return Done{arena->New<NominalClassValue>(act->results()[0], arg)};
|
||||
}
|
||||
case Value::Kind::AlternativeConstructorValue: {
|
||||
const auto& alt =
|
||||
cast<AlternativeConstructorValue>(*act->results()[0]);
|
||||
@@ -716,15 +687,9 @@ auto Interpreter::StepPattern() -> Transition {
|
||||
// H}
|
||||
// -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S,
|
||||
// H}
|
||||
return Spawn{
|
||||
arena->New<PatternAction>(tuple.Fields()[act->pos()].pattern)};
|
||||
return Spawn{arena->New<PatternAction>(tuple.Fields()[act->pos()])};
|
||||
} else {
|
||||
std::vector<TupleElement> elements;
|
||||
for (size_t i = 0; i < tuple.Fields().size(); ++i) {
|
||||
elements.push_back(
|
||||
{.name = tuple.Fields()[i].name, .value = act->results()[i]});
|
||||
}
|
||||
return Done{arena->New<TupleValue>(std::move(elements))};
|
||||
return Done{arena->New<TupleValue>(act->results())};
|
||||
}
|
||||
}
|
||||
case Pattern::Kind::AlternativePattern: {
|
||||
|
||||
@@ -126,8 +126,8 @@ static auto IsConcreteType(Nonnull<const Value*> value) -> bool {
|
||||
// `auto` isn't a concrete type, it's a pattern that matches types.
|
||||
return false;
|
||||
case Value::Kind::TupleValue:
|
||||
for (const TupleElement& field : cast<TupleValue>(*value).Elements()) {
|
||||
if (!IsConcreteType(field.value)) {
|
||||
for (Nonnull<const Value*> field : cast<TupleValue>(*value).Elements()) {
|
||||
if (!IsConcreteType(field)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -192,17 +192,16 @@ static auto IsImplicitlyConvertible(Nonnull<const Value*> source,
|
||||
case Value::Kind::TupleValue:
|
||||
switch (destination->kind()) {
|
||||
case Value::Kind::TupleValue: {
|
||||
const std::vector<TupleElement>& source_elements =
|
||||
const std::vector<Nonnull<const Value*>>& source_elements =
|
||||
cast<TupleValue>(*source).Elements();
|
||||
const std::vector<TupleElement>& destination_elements =
|
||||
const std::vector<Nonnull<const Value*>>& destination_elements =
|
||||
cast<TupleValue>(*destination).Elements();
|
||||
if (source_elements.size() != destination_elements.size()) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < source_elements.size(); ++i) {
|
||||
if (source_elements[i].name != destination_elements[i].name ||
|
||||
!IsImplicitlyConvertible(source_elements[i].value,
|
||||
destination_elements[i].value)) {
|
||||
if (!IsImplicitlyConvertible(source_elements[i],
|
||||
destination_elements[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -264,14 +263,9 @@ static auto ArgumentDeduction(SourceLocation source_loc, TypeEnv deduced,
|
||||
<< arg_tup.Elements().size();
|
||||
}
|
||||
for (size_t i = 0; i < param_tup.Elements().size(); ++i) {
|
||||
if (param_tup.Elements()[i].name != arg_tup.Elements()[i].name) {
|
||||
FATAL_COMPILATION_ERROR(source_loc)
|
||||
<< "mismatch in tuple names, " << param_tup.Elements()[i].name
|
||||
<< " != " << arg_tup.Elements()[i].name;
|
||||
}
|
||||
deduced = ArgumentDeduction(source_loc, deduced,
|
||||
param_tup.Elements()[i].value,
|
||||
arg_tup.Elements()[i].value);
|
||||
deduced =
|
||||
ArgumentDeduction(source_loc, deduced, param_tup.Elements()[i],
|
||||
arg_tup.Elements()[i]);
|
||||
}
|
||||
return deduced;
|
||||
}
|
||||
@@ -372,10 +366,9 @@ auto TypeChecker::Substitute(TypeEnv dict, Nonnull<const Value*> type)
|
||||
}
|
||||
}
|
||||
case Value::Kind::TupleValue: {
|
||||
std::vector<TupleElement> elts;
|
||||
std::vector<Nonnull<const Value*>> elts;
|
||||
for (const auto& elt : cast<TupleValue>(*type).Elements()) {
|
||||
auto t = Substitute(dict, elt.value);
|
||||
elts.push_back({.name = elt.name, .value = t});
|
||||
elts.push_back(Substitute(dict, elt));
|
||||
}
|
||||
return arena->New<TupleValue>(elts);
|
||||
}
|
||||
@@ -439,17 +432,15 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e, TypeEnv types,
|
||||
const Value& aggregate_type = index.aggregate().static_type();
|
||||
switch (aggregate_type.kind()) {
|
||||
case Value::Kind::TupleValue: {
|
||||
auto i =
|
||||
const auto& tuple_type = cast<TupleValue>(aggregate_type);
|
||||
int i =
|
||||
cast<IntValue>(*interpreter.InterpExp(values, &index.offset()))
|
||||
.Val();
|
||||
std::string f = std::to_string(i);
|
||||
std::optional<Nonnull<const Value*>> field_t =
|
||||
cast<TupleValue>(aggregate_type).FindField(f);
|
||||
if (!field_t) {
|
||||
if (i < 0 || i >= static_cast<int>(tuple_type.Elements().size())) {
|
||||
FATAL_COMPILATION_ERROR(e->source_loc())
|
||||
<< "field " << f << " is not in the tuple " << aggregate_type;
|
||||
<< "index " << i << " is out of range for type " << tuple_type;
|
||||
}
|
||||
SetStaticType(&index, *field_t);
|
||||
SetStaticType(&index, tuple_type.Elements()[i]);
|
||||
return TCResult(res.types);
|
||||
}
|
||||
default:
|
||||
@@ -457,15 +448,12 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e, TypeEnv types,
|
||||
}
|
||||
}
|
||||
case Expression::Kind::TupleLiteral: {
|
||||
std::vector<FieldInitializer> new_args;
|
||||
std::vector<TupleElement> arg_types;
|
||||
std::vector<Nonnull<const Value*>> arg_types;
|
||||
auto new_types = types;
|
||||
for (auto& arg : cast<TupleLiteral>(*e).fields()) {
|
||||
auto arg_res = TypeCheckExp(&arg.expression(), new_types, values);
|
||||
auto arg_res = TypeCheckExp(arg, new_types, values);
|
||||
new_types = arg_res.types;
|
||||
new_args.push_back(FieldInitializer(arg.name(), &arg.expression()));
|
||||
arg_types.push_back(
|
||||
{.name = arg.name(), .value = &arg.expression().static_type()});
|
||||
arg_types.push_back(&arg->static_type());
|
||||
}
|
||||
SetStaticType(e, arena->New<TupleValue>(std::move(arg_types)));
|
||||
return TCResult(new_types);
|
||||
@@ -542,18 +530,6 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e, TypeEnv types,
|
||||
<< "class " << t_class.Name() << " does not have a field named "
|
||||
<< access.field();
|
||||
}
|
||||
case Value::Kind::TupleValue: {
|
||||
const auto& tup = cast<TupleValue>(aggregate_type);
|
||||
for (const TupleElement& field : tup.Elements()) {
|
||||
if (access.field() == field.name) {
|
||||
SetStaticType(&access, field.value);
|
||||
return TCResult(res.types);
|
||||
}
|
||||
}
|
||||
FATAL_COMPILATION_ERROR(e->source_loc())
|
||||
<< "tuple " << tup << " does not have a field named "
|
||||
<< access.field();
|
||||
}
|
||||
case Value::Kind::ChoiceType: {
|
||||
const auto& choice = cast<ChoiceType>(aggregate_type);
|
||||
for (const auto& vt : choice.Alternatives()) {
|
||||
@@ -778,8 +754,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
}
|
||||
case Pattern::Kind::TuplePattern: {
|
||||
auto& tuple = cast<TuplePattern>(*p);
|
||||
std::vector<TuplePattern::Field> new_fields;
|
||||
std::vector<TupleElement> field_types;
|
||||
std::vector<Nonnull<const Value*>> field_types;
|
||||
auto new_types = types;
|
||||
if (expected && (*expected)->kind() != Value::Kind::TupleValue) {
|
||||
FATAL_COMPILATION_ERROR(p->source_loc()) << "didn't expect a tuple";
|
||||
@@ -790,24 +765,15 @@ auto TypeChecker::TypeCheckPattern(
|
||||
<< "tuples of different length";
|
||||
}
|
||||
for (size_t i = 0; i < tuple.Fields().size(); ++i) {
|
||||
TuplePattern::Field& field = tuple.Fields()[i];
|
||||
Nonnull<Pattern*> field = tuple.Fields()[i];
|
||||
std::optional<Nonnull<const Value*>> expected_field_type;
|
||||
if (expected) {
|
||||
const TupleElement& expected_element =
|
||||
cast<TupleValue>(**expected).Elements()[i];
|
||||
if (expected_element.name != field.name) {
|
||||
FATAL_COMPILATION_ERROR(tuple.source_loc())
|
||||
<< "field names do not match, expected "
|
||||
<< expected_element.name << " but got " << field.name;
|
||||
}
|
||||
expected_field_type = expected_element.value;
|
||||
expected_field_type = cast<TupleValue>(**expected).Elements()[i];
|
||||
}
|
||||
auto field_result = TypeCheckPattern(field.pattern, new_types, values,
|
||||
expected_field_type);
|
||||
auto field_result =
|
||||
TypeCheckPattern(field, new_types, values, expected_field_type);
|
||||
new_types = field_result.types;
|
||||
new_fields.push_back(TuplePattern::Field(field.name, field.pattern));
|
||||
field_types.push_back(
|
||||
{.name = field.name, .value = &field.pattern->static_type()});
|
||||
field_types.push_back(&field->static_type());
|
||||
}
|
||||
SetStaticType(&tuple, arena->New<TupleValue>(std::move(field_types)));
|
||||
return TCResult(new_types);
|
||||
@@ -1222,15 +1188,7 @@ void TypeChecker::TopLevel(Nonnull<Declaration*> d, TypeCheckContext* tops) {
|
||||
auto st = TypeOfClassDef(&class_def, tops->types, tops->values);
|
||||
Address a = interpreter.AllocateValue(st);
|
||||
tops->values.Set(class_def.name(), a); // Is this obsolete?
|
||||
std::vector<TupleElement> field_types;
|
||||
for (const auto& [field_name, field_value] :
|
||||
cast<NominalClassType>(*st).Fields()) {
|
||||
field_types.push_back({.name = field_name, .value = field_value});
|
||||
}
|
||||
auto fun_ty = arena->New<FunctionType>(
|
||||
std::vector<GenericBinding>(),
|
||||
arena->New<TupleValue>(std::move(field_types)), st);
|
||||
tops->types.Set(class_def.name(), fun_ty);
|
||||
tops->types.Set(class_def.name(), st);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,17 +46,7 @@ auto FieldsEqual(const VarValues& ts1, const VarValues& ts2) -> bool {
|
||||
|
||||
auto StructValue::FindField(const std::string& name) const
|
||||
-> std::optional<Nonnull<const Value*>> {
|
||||
for (const TupleElement& element : elements_) {
|
||||
if (element.name == name) {
|
||||
return element.value;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto TupleValue::FindField(const std::string& name) const
|
||||
-> std::optional<Nonnull<const Value*>> {
|
||||
for (const TupleElement& element : elements) {
|
||||
for (const StructElement& element : elements_) {
|
||||
if (element.name == name) {
|
||||
return element.value;
|
||||
}
|
||||
@@ -80,20 +70,12 @@ auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
|
||||
}
|
||||
case Value::Kind::NominalClassValue: {
|
||||
std::optional<Nonnull<const Value*>> field =
|
||||
cast<TupleValue>(*cast<NominalClassValue>(*v).Inits()).FindField(f);
|
||||
cast<StructValue>(*cast<NominalClassValue>(*v).Inits()).FindField(f);
|
||||
if (field == std::nullopt) {
|
||||
FATAL_RUNTIME_ERROR(source_loc) << "member " << f << " not in " << *v;
|
||||
}
|
||||
return *field;
|
||||
}
|
||||
case Value::Kind::TupleValue: {
|
||||
std::optional<Nonnull<const Value*>> field =
|
||||
cast<TupleValue>(*v).FindField(f);
|
||||
if (!field) {
|
||||
FATAL_RUNTIME_ERROR(source_loc) << "field " << f << " not in " << *v;
|
||||
}
|
||||
return *field;
|
||||
}
|
||||
case Value::Kind::ChoiceType: {
|
||||
const auto& choice = cast<ChoiceType>(*v);
|
||||
if (!FindInVarValues(f, choice.Alternatives())) {
|
||||
@@ -130,9 +112,10 @@ auto SetFieldImpl(Nonnull<Arena*> arena, Nonnull<const Value*> value,
|
||||
}
|
||||
switch (value->kind()) {
|
||||
case Value::Kind::StructValue: {
|
||||
std::vector<TupleElement> elements = cast<StructValue>(*value).elements();
|
||||
std::vector<StructElement> elements =
|
||||
cast<StructValue>(*value).elements();
|
||||
auto it = std::find_if(elements.begin(), elements.end(),
|
||||
[path_begin](const TupleElement& element) {
|
||||
[path_begin](const StructElement& element) {
|
||||
return element.name == *path_begin;
|
||||
});
|
||||
if (it == elements.end()) {
|
||||
@@ -148,17 +131,16 @@ auto SetFieldImpl(Nonnull<Arena*> arena, Nonnull<const Value*> value,
|
||||
path_begin, path_end, field_value, source_loc);
|
||||
}
|
||||
case Value::Kind::TupleValue: {
|
||||
std::vector<TupleElement> elements = cast<TupleValue>(*value).Elements();
|
||||
auto it = std::find_if(elements.begin(), elements.end(),
|
||||
[path_begin](const TupleElement& element) {
|
||||
return element.name == *path_begin;
|
||||
});
|
||||
if (it == elements.end()) {
|
||||
std::vector<Nonnull<const Value*>> elements =
|
||||
cast<TupleValue>(*value).Elements();
|
||||
// TODO(geoffromer): update FieldPath to hold integers as well as strings.
|
||||
int index = std::stoi(*path_begin);
|
||||
if (index < 0 || static_cast<size_t>(index) >= elements.size()) {
|
||||
FATAL_RUNTIME_ERROR(source_loc)
|
||||
<< "field " << *path_begin << " not in " << *value;
|
||||
<< "index " << *path_begin << " out of range in " << *value;
|
||||
}
|
||||
it->value = SetFieldImpl(arena, it->value, path_begin + 1, path_end,
|
||||
field_value, source_loc);
|
||||
elements[index] = SetFieldImpl(arena, elements[index], path_begin + 1,
|
||||
path_end, field_value, source_loc);
|
||||
return arena->New<TupleValue>(elements);
|
||||
}
|
||||
default:
|
||||
@@ -203,7 +185,7 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
const auto& struct_val = cast<StructValue>(*this);
|
||||
out << "{";
|
||||
llvm::ListSeparator sep;
|
||||
for (const TupleElement& element : struct_val.elements()) {
|
||||
for (const StructElement& element : struct_val.elements()) {
|
||||
out << sep << "." << element.name << " = " << *element.value;
|
||||
}
|
||||
out << "}";
|
||||
@@ -217,8 +199,8 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
case Value::Kind::TupleValue: {
|
||||
out << "(";
|
||||
llvm::ListSeparator sep;
|
||||
for (const TupleElement& element : cast<TupleValue>(*this).Elements()) {
|
||||
out << sep << element.name << " = " << *element.value;
|
||||
for (Nonnull<const Value*> element : cast<TupleValue>(*this).Elements()) {
|
||||
out << sep << *element;
|
||||
}
|
||||
out << ")";
|
||||
break;
|
||||
@@ -313,11 +295,9 @@ auto CopyVal(Nonnull<Arena*> arena, Nonnull<const Value*> val,
|
||||
SourceLocation source_loc) -> Nonnull<const Value*> {
|
||||
switch (val->kind()) {
|
||||
case Value::Kind::TupleValue: {
|
||||
std::vector<TupleElement> elements;
|
||||
for (const TupleElement& element : cast<TupleValue>(*val).Elements()) {
|
||||
elements.push_back(
|
||||
{.name = element.name,
|
||||
.value = CopyVal(arena, element.value, source_loc)});
|
||||
std::vector<Nonnull<const Value*>> elements;
|
||||
for (Nonnull<const Value*> element : cast<TupleValue>(*val).Elements()) {
|
||||
elements.push_back(CopyVal(arena, element, source_loc));
|
||||
}
|
||||
return arena->New<TupleValue>(std::move(elements));
|
||||
}
|
||||
@@ -327,8 +307,8 @@ auto CopyVal(Nonnull<Arena*> arena, Nonnull<const Value*> val,
|
||||
return arena->New<AlternativeValue>(alt.AltName(), alt.ChoiceName(), arg);
|
||||
}
|
||||
case Value::Kind::StructValue: {
|
||||
std::vector<TupleElement> elements;
|
||||
for (const TupleElement& element : cast<StructValue>(*val).elements()) {
|
||||
std::vector<StructElement> elements;
|
||||
for (const StructElement& element : cast<StructValue>(*val).elements()) {
|
||||
elements.push_back(
|
||||
{.name = element.name,
|
||||
.value = CopyVal(arena, element.value, source_loc)});
|
||||
@@ -435,8 +415,7 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2) -> bool {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < tup1.Elements().size(); ++i) {
|
||||
if (tup1.Elements()[i].name != tup2.Elements()[i].name ||
|
||||
!TypeEqual(tup1.Elements()[i].value, tup2.Elements()[i].value)) {
|
||||
if (!TypeEqual(tup1.Elements()[i], tup2.Elements()[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -459,16 +438,16 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2) -> bool {
|
||||
|
||||
// Returns true if all the fields of the two tuples contain equal values
|
||||
// and returns false otherwise.
|
||||
static auto FieldsValueEqual(const std::vector<TupleElement>& ts1,
|
||||
const std::vector<TupleElement>& ts2,
|
||||
static auto FieldsValueEqual(const std::vector<StructElement>& ts1,
|
||||
const std::vector<StructElement>& ts2,
|
||||
SourceLocation source_loc) -> bool {
|
||||
if (ts1.size() != ts2.size()) {
|
||||
return false;
|
||||
}
|
||||
for (const TupleElement& element : ts1) {
|
||||
for (const StructElement& element : ts1) {
|
||||
auto iter = std::find_if(
|
||||
ts2.begin(), ts2.end(),
|
||||
[&](const TupleElement& e2) { return e2.name == element.name; });
|
||||
[&](const StructElement& e2) { return e2.name == element.name; });
|
||||
if (iter == ts2.end()) {
|
||||
return false;
|
||||
}
|
||||
@@ -502,9 +481,21 @@ auto ValueEqual(Nonnull<const Value*> v1, Nonnull<const Value*> v2,
|
||||
return body1.has_value() == body2.has_value() &&
|
||||
(!body1.has_value() || *body1 == *body2);
|
||||
}
|
||||
case Value::Kind::TupleValue:
|
||||
return FieldsValueEqual(cast<TupleValue>(*v1).Elements(),
|
||||
cast<TupleValue>(*v2).Elements(), source_loc);
|
||||
case Value::Kind::TupleValue: {
|
||||
const std::vector<Nonnull<const Value*>>& elements1 =
|
||||
cast<TupleValue>(*v1).Elements();
|
||||
const std::vector<Nonnull<const Value*>>& elements2 =
|
||||
cast<TupleValue>(*v2).Elements();
|
||||
if (elements1.size() != elements2.size()) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < elements1.size(); ++i) {
|
||||
if (!ValueEqual(elements1[i], elements2[i], source_loc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Value::Kind::StructValue:
|
||||
return FieldsValueEqual(cast<StructValue>(*v1).elements(),
|
||||
cast<StructValue>(*v2).elements(), source_loc);
|
||||
|
||||
@@ -94,12 +94,11 @@ auto FindInVarValues(const std::string& field, const VarValues& inits)
|
||||
-> std::optional<Nonnull<const Value*>>;
|
||||
auto FieldsEqual(const VarValues& ts1, const VarValues& ts2) -> bool;
|
||||
|
||||
// A TupleElement represents the value of a single tuple or struct field.
|
||||
// A StructElement represents the value of a single struct field.
|
||||
//
|
||||
// TODO(geoffromer): Rename this, and look for ways to eliminate duplication
|
||||
// among TupleElement, VarValues::value_type, FieldInitializer,
|
||||
// TuplePattern::Field, and any similar types.
|
||||
struct TupleElement {
|
||||
// TODO(geoffromer): Look for ways to eliminate duplication among StructElement,
|
||||
// VarValues::value_type, FieldInitializer, and any similar types.
|
||||
struct StructElement {
|
||||
// The field name.
|
||||
std::string name;
|
||||
|
||||
@@ -188,7 +187,7 @@ class BoolValue : public Value {
|
||||
// StructType instances.
|
||||
class StructValue : public Value {
|
||||
public:
|
||||
explicit StructValue(std::vector<TupleElement> elements)
|
||||
explicit StructValue(std::vector<StructElement> elements)
|
||||
: Value(Kind::StructValue), elements_(std::move(elements)) {
|
||||
CHECK(!elements_.empty())
|
||||
<< "`{}` is represented as a StructType, not a StructValue.";
|
||||
@@ -198,7 +197,7 @@ class StructValue : public Value {
|
||||
return value->kind() == Kind::StructValue;
|
||||
}
|
||||
|
||||
auto elements() const -> const std::vector<TupleElement>& {
|
||||
auto elements() const -> const std::vector<StructElement>& {
|
||||
return elements_;
|
||||
}
|
||||
|
||||
@@ -208,7 +207,7 @@ class StructValue : public Value {
|
||||
-> std::optional<Nonnull<const Value*>>;
|
||||
|
||||
private:
|
||||
std::vector<TupleElement> elements_;
|
||||
std::vector<StructElement> elements_;
|
||||
};
|
||||
|
||||
// A value of a nominal class type.
|
||||
@@ -278,26 +277,24 @@ class TupleValue : public Value {
|
||||
public:
|
||||
// An empty tuple, also known as the unit type.
|
||||
static auto Empty() -> Nonnull<const TupleValue*> {
|
||||
static const TupleValue empty = TupleValue(std::vector<TupleElement>());
|
||||
static const TupleValue empty =
|
||||
TupleValue(std::vector<Nonnull<const Value*>>());
|
||||
return Nonnull<const TupleValue*>(&empty);
|
||||
}
|
||||
|
||||
explicit TupleValue(std::vector<TupleElement> elements)
|
||||
explicit TupleValue(std::vector<Nonnull<const Value*>> elements)
|
||||
: Value(Kind::TupleValue), elements(std::move(elements)) {}
|
||||
|
||||
static auto classof(const Value* value) -> bool {
|
||||
return value->kind() == Kind::TupleValue;
|
||||
}
|
||||
|
||||
auto Elements() const -> const std::vector<TupleElement>& { return elements; }
|
||||
|
||||
// Returns the value of the field named `name` in this tuple, or
|
||||
// nullopt if there is no such field.
|
||||
auto FindField(const std::string& name) const
|
||||
-> std::optional<Nonnull<const Value*>>;
|
||||
auto Elements() const -> const std::vector<Nonnull<const Value*>>& {
|
||||
return elements;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<TupleElement> elements;
|
||||
std::vector<Nonnull<const Value*>> elements;
|
||||
};
|
||||
|
||||
// A binding placeholder value.
|
||||
|
||||
Reference in New Issue
Block a user