Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature generic choice #2042

Merged
merged 20 commits into from
Aug 24, 2022
Merged

Conversation

pmqtt
Copy link
Contributor

@pmqtt pmqtt commented Aug 16, 2022

Implementation of generic choices!

I hope it is useful!

Copy link

@kmz42 kmz42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few thoughts. Still new to the project so feel free to tell me i'm wrong. Nice PR 🎉

@@ -838,7 +838,26 @@ class ChoiceType : public Value {
ChoiceType(std::string name, std::vector<NamedValue> alternatives)
: Value(Kind::ChoiceType),
name_(std::move(name)),
alternatives_(std::move(alternatives)) {}
alternatives_(std::move(alternatives)),
is_generic_(false) {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need is_generic_? Isn't it implied by the presence or absence of bindings (as with NominalClassType)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we need is_generic! NominalClassType can check over type_args that binding is present or not.

alternatives_(std::move(alternatives)),
is_generic_(false) {}

ChoiceType(std::string name, std::vector<NamedValue> alternatives,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe i'm missing context but why do we even have a ChoiceType constructor that uses std::string name instead of only a ChoiceDeclaration?

It looks like the pattern we're using in existing choice code is arena_->New<ChoiceType>(choice->name(), ... to construct with the name instead of the ChoiceDeclaration. Is there a reason we shouldn't always construct with the ChoiceDeclaration?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, one more thing, could you add comments to each constructor briefly describing the use case for that constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I try to minimalize code changes! This is the reason why I have not refector this part. But you are right, this should the next step after merging this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you are right, this should the next step after merging this PR.

I think it would be simpler to make that change first. Several of the issues I've flagged in other comments would be easier to address that way, and it keeps the API more consistent.

@@ -0,0 +1,30 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add a few more tests, particularly negative tests?

There's a bunch for generic class tests in testdata/generic_class. Probably a few of those could become good choice tests.

Copy link
Contributor

@geoffromer geoffromer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks really helpful!

auto type_args() const -> const BindingMap& { return bindings_->args(); }
auto declaration() const -> const ChoiceDeclaration& { return *declaration_; }

auto is_generic() const -> bool { return is_generic_; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with NominalClassType, it seems like this should be called IsParameterized, and the return value should be computed from declaration_ and bindings_ rather than stored in a separate data member.

alternatives_(std::move(alternatives)),
is_generic_(false) {}

ChoiceType(std::string name, std::vector<NamedValue> alternatives,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you are right, this should the next step after merging this PR.

I think it would be simpler to make that change first. Several of the issues I've flagged in other comments would be easier to address that way, and it keeps the API more consistent.

Comment on lines 873 to 875
auto bindings() const -> const Bindings& { return *bindings_; }
auto type_args() const -> const BindingMap& { return bindings_->args(); }
auto declaration() const -> const ChoiceDeclaration& { return *declaration_; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it's not safe to call these methods if the object was created using the first constructor.


private:
Nonnull<const Declaration*> declaration_;
Nonnull<const TuplePattern*> params_;
std::vector<NamedValue> alternatives_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, ParameterizedEntityName represents a name. In other words, in an expression like Optional(i32), it represents the Optional part. That being the case, it seems really weird for this class to have a list of alternatives as a data member. Could the code that needs the alternatives get them out of declaration instead?

@@ -0,0 +1,30 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"generic_choice1" isn't a very descriptive file name. What is this file actually testing that isn't covered by generic_choice.carbon?

@pmqtt
Copy link
Contributor Author

pmqtt commented Aug 17, 2022

Hello folks, geoffromer and kmz42,
first thanks for the review. I have rename the test files and prettify the code ( reduceing the constructor count).
Second, I know that store alternatives in ParameterizedType is weird. The reason is, after the type checking process the Interpreter process need this information. The ChoiceDeclaration stores AlternativeSignatures and the ChoiceType need NamedValues. Without a futher type checking step isn't possible to get the NamedValue. Possible solutions are

  1. Allow ChoiceDeclaration to store NamedValues
  2. Change the interpreter that generic choices not handle by CallFunction
  3. Renaming the ParametrizedType to....?

Another point is, if we want to create the NamedValue in the type checking process TypeCheckPattern and TypeCheckExp we need const_cast. The resulting code is really weird and ugly.

@geoffromer have you any ideas, or should we start with my solution?

@pmqtt pmqtt requested a review from geoffromer August 17, 2022 14:09
@pmqtt
Copy link
Contributor Author

pmqtt commented Aug 19, 2022

@geoffromer I must apologize... I had thought NamedValue was derived from Value. This is not true, so it is possible to store the Choice-alternatives in the ChoiceDeclaration object.

@pmqtt pmqtt requested review from kmz42 and geoffromer and removed request for geoffromer and kmz42 August 19, 2022 09:28
Copy link
Contributor

@jonmeow jonmeow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To note on style˛I think there are always going to be differences on preferences for what style is used. While I'm happy to point out style guide issues, I also think it can be beneficial to avoid changing code when there's not a correctness or readability problem. Otherwise, someone else could end up sending a PR to change it back with equivalent justification.

Comment on lines 841 to 842
name_(declaration->name()),
alternatives_(declaration->members()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these copies needed? Since you've started keeping a ChoiceDeclaration for IsParameterized, should name() and FindAlternative use it directly too?

@@ -2205,8 +2215,11 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
}
case ExpressionKind::CallExpression: {
auto& call = cast<CallExpression>(*e);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're adding a lot of blank lines in this file around code that you're not otherwise editing. The rule of thumb is to minimize vertical whitespace (https://google.github.io/styleguide/cppguide.html#Vertical_Whitespace), and while I think it can be useful to separate code blocks, I think separating out single lines is probably a little more than is needed. Can you please do a pass reducing the whitespace back down?

Comment on lines 3888 to 3889
auto TypeChecker::TypeCheckChoiceDeclaration(Nonnull<ChoiceDeclaration*> choice,
const ImplScope& impl_scope)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were commented out to indicate they were unused. They probably should not be uncommented in this PR, because uses are not added.

Comment on lines 568 to 570
// Alternative names are never used unqualified, so we don't need to
// add the alternatives to a scope, or introduce a new scope; we only
// need to check for duplicates.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment seems to be referring to the below for loop, and probably shouldn't be separated from it, particularly with a blank line.

Comment on lines 2250 to 2254
const TypeOfParameterizedEntityName& entity =
cast<TypeOfParameterizedEntityName>(
call.function().static_type());

const ParameterizedEntityName& param_name = entity.name();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it's not necessary to change. I'm not seeing a particular style benefit to it, and you don't make use of entity. Can you please switch back so that we're not changing code when not necessary?

@jonmeow
Copy link
Contributor

jonmeow commented Aug 24, 2022

** picking up this review since geoffromer is out

@pmqtt pmqtt requested a review from jonmeow August 24, 2022 17:54
Copy link
Contributor

@jonmeow jonmeow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'm happy to have this in.

@jonmeow jonmeow dismissed geoffromer’s stale review August 24, 2022 17:59

Going on vacation

@jonmeow jonmeow merged commit f957d4d into carbon-language:trunk Aug 24, 2022
@chandlerc chandlerc added the explorer Action items related to Carbon explorer code label Jan 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
explorer Action items related to Carbon explorer code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants