-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Make the AST mutable #849
Make the AST mutable #849
Conversation
@@ -108,22 +110,21 @@ class ChoiceDeclaration : public Declaration { | |||
} | |||
|
|||
auto Name() const -> const std::string& { return name; } | |||
auto Alternatives() const -> const | |||
std::vector<std::pair<std::string, Nonnull<const Expression*>>>& { | |||
auto Alternatives() const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a const method, but it's giving non-const access to the expressions, which I don't think is right. To fix that, I think we'll need to replace std::pair
with a proper class with its own const/non-const accessor pair (which IMO we should do anyway). Assuming you don't want to do that in this PR, could we add a TODO, and switch alternatives
back to std::vector<std::pair<std::string, Nonnull<const Expression*>>>
in the meantime?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing this in #853
@@ -43,10 +42,10 @@ struct FunctionDefinition { | |||
SourceLocation source_location; | |||
std::string name; | |||
std::vector<GenericBinding> deduced_parameters; | |||
Nonnull<const TuplePattern*> param_pattern; | |||
Nonnull<const Pattern*> return_type; | |||
Nonnull<TuplePattern*> param_pattern; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will allow code holding a const FunctionDefinition*
to mutate that definition's parameters. To fix that, I think we'll need to either turn this struct into a class with const/non-const accessors, or wrap the pointer members in something like propagate_const
. And unfortunately, I think the same goes for pretty much every pointer member of every struct that this PR touches (but it looks like maybe there aren't too many of those?).
If you don't want to do that in this PR, could we add the const back to those members, and flag it with a TODO?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switching in #852, that'll block this PR
@@ -248,7 +248,7 @@ auto TypeChecker::Substitute(TypeEnv dict, Nonnull<const Value*> type) | |||
} | |||
} | |||
|
|||
auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types, | |||
auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e, TypeEnv types, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the rationale for dropping the const
here? AFAICT this function doesn't actually need mutable access unless/until we update it to modify the AST in place rather than producing a copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to explain on #executable_semantics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To recap for future reference, the key issue is that in some circumstances, TypeCheckExp
will reuse the input AST node as part of the output. That means in order for the output to be mutable, the input needs to be mutable. I think it's an open question whether that's the right approach long-term, but I think for purposes of this PR, keeping it non-const makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to break out related PRs rather than doing class refactorings here, discussing in #executable_semantics
@@ -248,7 +248,7 @@ auto TypeChecker::Substitute(TypeEnv dict, Nonnull<const Value*> type) | |||
} | |||
} | |||
|
|||
auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types, | |||
auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e, TypeEnv types, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to explain on #executable_semantics
@@ -43,10 +42,10 @@ struct FunctionDefinition { | |||
SourceLocation source_location; | |||
std::string name; | |||
std::vector<GenericBinding> deduced_parameters; | |||
Nonnull<const TuplePattern*> param_pattern; | |||
Nonnull<const Pattern*> return_type; | |||
Nonnull<TuplePattern*> param_pattern; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switching in #852, that'll block this PR
@@ -108,22 +110,21 @@ class ChoiceDeclaration : public Declaration { | |||
} | |||
|
|||
auto Name() const -> const std::string& { return name; } | |||
auto Alternatives() const -> const | |||
std::vector<std::pair<std::string, Nonnull<const Expression*>>>& { | |||
auto Alternatives() const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing this in #853
Splitting out the task from #849
@@ -248,7 +248,7 @@ auto TypeChecker::Substitute(TypeEnv dict, Nonnull<const Value*> type) | |||
} | |||
} | |||
|
|||
auto TypeChecker::TypeCheckExp(Nonnull<const Expression*> e, TypeEnv types, | |||
auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e, TypeEnv types, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To recap for future reference, the key issue is that in some circumstances, TypeCheckExp
will reuse the input AST node as part of the output. That means in order for the output to be mutable, the input needs to be mutable. I think it's an open question whether that's the right approach long-term, but I think for purposes of this PR, keeping it non-const makes sense.
Splitting out the task from #849
The code is pretty intertwined: having the AST be truly mutable means (to me) changing parser.ypp to return non-const values, but then the way things are passed around between objects should be non-const (particularly an issue with lists), which then creates issues with construction of lists in the TypeChecker, which then TypeChecker needs to mostly be non-const. Due to the difficulties in breaking this apart, whereas I'd previously considering refactoring accessor naming in the same PR, I've largely avoided doing so. The intent is then that this PR focuses mainly on const -> non-const AST behavior. call_main moves out of interpreter.cpp so that interpreter.cpp can receive a fully const AST.
The code is pretty intertwined: having the AST be truly mutable means (to me) changing parser.ypp to return non-const values, but then the way things are passed around between objects should be non-const (particularly an issue with lists), which then creates issues with construction of lists in the TypeChecker, which then TypeChecker needs to mostly be non-const.
Due to the difficulties in breaking this apart, whereas I'd previously considering refactoring accessor naming in the same PR, I've largely avoided doing so. The intent is then that this PR focuses mainly on const -> non-const AST behavior.
call_main moves out of interpreter.cpp so that interpreter.cpp can receive a fully const AST.