-
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
Parsing and basic checking for abstract class
and base class
.
#3385
Conversation
toolchain/check/convert.cpp
Outdated
if (class_info.inheritance_kind == SemIR::Class::Abstract) { | ||
CARBON_DIAGNOSTIC(ConstructionOfAbstractClass, Error, | ||
"Cannot construct instance of abstract class `{0}`. " | ||
"Consider using `partial` class type instead.", |
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.
class type -> facet?
https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/classes.md#partial-facet
"Consider using `partial` class type instead.", | |
"Consider using `partial` facet type instead.", |
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.
@josh11b I think that's out of date; we use "facet" to mean a value of facet type these days, and it seems confusing to also use it here. (It wouldn't be wrong, because every type is a facet, because type
is a facet type, but it seems at least misleading.)
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.
I agree that we've changed how we use the word "facet" since https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/classes.md#partial-facet was written. I don't have a good replacement term at the moment. "partial class type" would be fine with me until we have that discussion, though should it be "partial-class type"?
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.
I'm trying to suggest specifically using the partial
keyword here. I suppose we could use
"Cannot construct instance of abstract class. "
"Consider using `partial {0}` instead.",
Thoughts, preferences?
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.
I've switched to the partial {0}
approach for now.
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.
I could go either way on this; I think the change is fine to keep.
// result in a `set_packaging_state` call. Note, this may not always be | ||
// necessary but is probably cheaper than validating. | ||
switch (position_kind) { | ||
case Lex::TokenKind::Abstract: { |
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 would you think of pushing abstract
and base
handling out of this file, and into their own state? That way, the general declaration scope handling doesn't start to become specialized towards handling specific syntaxes, which would make the file scale up in size. Perhaps that would also allow for aa setup that didn't need to change the handling of interface
or class
in this file, allowing Consume
to continue to be done locally within handlers.
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.
I tried that first, but ended up with lots of extra states that seemed to be making the parsing more complicated. Maybe we can take another look as a follow-up?
One thing I have in the back of my mind here is what this will look like once we handle more modifiers: I've been imagining that we'd (effectively) have a loop consuming them until it hits an introducer, and then producing the introducer node followed by the modifiers (in their original order). And I think that doesn't easily fall out of a stack-based approach: the stack would reverse the order of modifiers, and we'll want to push an introducer-specific state to parse the rest of whatever we found which should be run after we add the modifier nodes, requiring pushing to somewhere that's not the top of the stack. It seems to me like using the state stack to model that would require that we do some mutation and/or reordering of the stack once we hit the introducer. Maybe that's OK though? We already do something like that for tuples.
Another possibility would be to do lookahead from the start of a declaration to find the introducer token, and enter the right state for it and immediately build its parse node. Then, it can handle its own modifiers in whatever way makes sense, and just skip the introducer token once it's reached. (We'd effectively be parsing as if we first reordered public abstract class X
to class public abstract X
.)
In any case, I'd prefer to dig into this in a separate PR, once we have more modifiers that we need to support, if that works for you?
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.
I'm a little wary here, particularly due to the addition of peeking in PositionIs and PositionKind to support something that I think should be removed. We can proceed, but can you add a TODO to those functions to suggest avoiding/removing the depth argument if possible?
Co-authored-by: Jon Ross-Perkins <[email protected]>
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.
Approving, hopefully the related #toolchain discussion yields a good improvement.
its use and a TODO to consider removing it altogether.
For now, we require the same introducer to be used each time a class is declared, but see #3384.