-
-
Notifications
You must be signed in to change notification settings - Fork 647
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
Support abstract
modifier on classes and methods
#9716
Conversation
@@ -2261,7 +2261,7 @@ let generate con = | |||
| overloads -> overloads | |||
in | |||
List.iter (fun cf -> | |||
if (has_class_flag cl CInterface) || cf.cf_expr <> None then | |||
if (has_class_flag cl CInterface) || (has_class_flag cl CAbstract) || cf.cf_expr <> None then |
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 think we should aim to generate native abstract classes where supported. But that could be done later.
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.
Actually, I think we have to do it right away. Otherwise we run into problems if an abstract method has a return type since we can't just generate an empty block for it...
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.
Ah, ok
Why |
For consistency. All other class-specific modifiers are allowed on interfaces as well and only fail during typing, so I figured we should do this for |
This PR is missing an implementation of the following statement from the proposal:
|
Also inlining is not treated well. The following sample should emit two errors, but none are emitted: class Main {
static function main() {
var w:Abstr = null;
inline w.test(); // Missing error: Cannot inline abstract method
}
}
abstract class Abstr {
abstract public inline function test():Void; // Missing error: Inline function cannot be abstract
} |
Yeah, hmm... this might introduce some typing pass concerns if we generate these fields at the time we verify the interface. There might also be some complications once overloads get involved because we have to manage Can we hold back on this change for now? |
Sure. It won't be a breaking change to allow that later. |
I've just tried to implement this out of curiosity and indeed ran into the typing pass problem. It seems to work by changing the interface check from So, anything else? |
This requires generator updates for HL, hxcpp and PHP. @RealyUniqueName Could you handle PHP? I'll try to figure out the others. |
LGTM
I mean it's not necessary to be a part of this PR. |
Sorry, by "this" I'm referring to this PR in general. I thought it was passing, but that was only because I was using |
@hughsando Could you check the gencpp.ml changes here? I've implemented abstract methods to be generated as pure virtual functions, and then had to fiddle around a lot to get the |
src/generators/gencpp.ml
Outdated
output (" " ^ remap_name ^ "(" ); | ||
output (ctx_arg_list ctx tl "" ); | ||
output ") = 0;\n"; | ||
output (" virtual ::Dynamic " ^ remap_name ^ "_dyn();\n" ); |
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 don't think this function should be virtual, since internally it will call a virtual function.
Then, it is not needed if the "doDynamic" logic (nonVirtual || not (is_override field ) ) && (reflective class_def field )
is not required. This would be the case when one declared abstract method also exists in a parent class, or it is declared "@:unreflective"
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.
Right, good point. I've changed that in 7010960
Alright, CI is green! I'll go ahead and merge this now. There are probably some details that can be improved in various generators, but we can do that later. |
This PR adds support for abstract classes.
At syntax-level, we allow
abstract
as a modifier for both classes and fields. We also allow parsingabstract interface
, but bothabstract typedef
andabstract abstract
are parser errors.During type-loading, there's a bunch of checks for invalid combinations, such as
abstract final
. See the tests for details.The abstract property is as follows:
abstract
, the class itself must be marked asabstract
. We can debate later if we want to keep this mandatory (in fact, we already infer the class to be abstract in order to avoid repeating errors).abstract
, it must not have an expression.abstract
, bothnew ThatClass()
andThatClass.new
are disallowed.abstract
class, it must either be madeabstract
itself or implement allabstract
member methods of the extended class and all its parent classes.That last part is implemented in
check_abstract_class
. It is implemented with overload support, which lead to the following algorithm:Given a non-abstract class
C
extending an abstract classAC
:AC
and all its parent classes.AC
and all its parent classes.cf
:cf
isn't markedabstract
, ignore it.C
doesn't implementcf
, add it to amissing
listmissing
isn't empty, emit an appropriate error.A class is considered to implement an overload
cf
if it has a method with the same name for whichOverloads.same_overload_args
is true. That's how we check overload equality in general.