Expect parentheses after an alternative only if they were present in its declaration (#2605)

The design of choice types expects the declaration of an alternative to match the usage: if an alternative is declared as `None`, then it should be used as `None` not `None()`, and if it is declared as `None()` then it should be used as `None()` not `None`. Update explorer to match.

Also clean up the handling of choice types and alternative values a little in general, by moving away from identifying choice types and alternatives as strings and towards identifying them symbolically.

Closes #2422
This commit is contained in:
Richard Smith
2023-02-14 13:28:52 -08:00
committed by GitHub
parent f7924aa93f
commit 59ff7743c0
18 changed files with 315 additions and 168 deletions
+31 -20
View File
@@ -195,11 +195,15 @@ static auto GetNamedElement(Nonnull<Arena*> arena, Nonnull<const Value*> v,
}
case Value::Kind::ChoiceType: {
const auto& choice = cast<ChoiceType>(*v);
if (!choice.FindAlternative(f)) {
auto alt = choice.declaration().FindAlternative(f);
if (!alt) {
return ProgramError(source_loc)
<< "alternative " << f << " not in " << *v;
}
return arena->New<AlternativeConstructorValue>(f, choice.name());
if ((*alt)->signature()) {
return arena->New<AlternativeConstructorValue>(&choice, *alt);
}
return arena->New<AlternativeValue>(&choice, *alt, std::nullopt);
}
case Value::Kind::NominalClassType: {
// Access a class function.
@@ -360,7 +364,8 @@ void Value::Print(llvm::raw_ostream& out) const {
switch (kind()) {
case Value::Kind::AlternativeConstructorValue: {
const auto& alt = cast<AlternativeConstructorValue>(*this);
out << alt.choice_name() << "." << alt.alt_name();
out << alt.choice().declaration().name() << "."
<< alt.alternative().name();
break;
}
case Value::Kind::BindingPlaceholderValue: {
@@ -381,8 +386,11 @@ void Value::Print(llvm::raw_ostream& out) const {
}
case Value::Kind::AlternativeValue: {
const auto& alt = cast<AlternativeValue>(*this);
out << "alt " << alt.choice_name() << "." << alt.alt_name() << " "
<< alt.argument();
out << alt.choice().declaration().name() << "."
<< alt.alternative().name();
if (auto arg = alt.argument()) {
out << **arg;
}
break;
}
case Value::Kind::StructValue: {
@@ -536,6 +544,13 @@ void Value::Print(llvm::raw_ostream& out) const {
}
break;
}
case Value::Kind::ChoiceType: {
const auto& choice_type = cast<ChoiceType>(*this);
out << "choice ";
PrintNameWithBindings(out, &choice_type.declaration(),
choice_type.type_args());
break;
}
case Value::Kind::MixinPseudoType: {
const auto& mixin_type = cast<MixinPseudoType>(*this);
out << "mixin ";
@@ -647,9 +662,6 @@ void Value::Print(llvm::raw_ostream& out) const {
}
break;
}
case Value::Kind::ChoiceType:
out << "choice " << cast<ChoiceType>(*this).name();
break;
case Value::Kind::VariableType:
out << cast<VariableType>(*this).binding().name();
break;
@@ -1013,6 +1025,17 @@ auto ValueStructurallyEqual(
}
return true;
}
case Value::Kind::AlternativeValue: {
const auto& alt1 = cast<AlternativeValue>(*v1);
const auto& alt2 = cast<AlternativeValue>(*v2);
if (!TypeEqual(&alt1.choice(), &alt2.choice(), equality_ctx) ||
&alt1.alternative() != &alt2.alternative()) {
return false;
}
CARBON_CHECK(alt1.argument().has_value() == alt2.argument().has_value());
return !alt1.argument().has_value() ||
ValueEqual(*alt1.argument(), *alt2.argument(), equality_ctx);
}
case Value::Kind::StringValue:
return cast<StringValue>(*v1).value() == cast<StringValue>(*v2).value();
case Value::Kind::ParameterizedEntityName: {
@@ -1059,7 +1082,6 @@ auto ValueStructurallyEqual(
case Value::Kind::StaticArrayType:
return TypeEqual(v1, v2, equality_ctx);
case Value::Kind::NominalClassValue:
case Value::Kind::AlternativeValue:
case Value::Kind::BindingPlaceholderValue:
case Value::Kind::AddrValue:
case Value::Kind::AlternativeConstructorValue:
@@ -1151,17 +1173,6 @@ auto ConstraintType::VisitEqualValues(
return true;
}
auto ChoiceType::FindAlternative(std::string_view name) const
-> std::optional<Nonnull<const Value*>> {
std::vector<NamedValue> alternatives = declaration_->members();
for (const NamedValue& alternative : alternatives) {
if (alternative.name == name) {
return alternative.value;
}
}
return std::nullopt;
}
auto FindFunction(std::string_view name,
llvm::ArrayRef<Nonnull<Declaration*>> members)
-> std::optional<Nonnull<const FunctionValue*>> {