-
-
Notifications
You must be signed in to change notification settings - Fork 670
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
Interfaces, Abstract Methods, and Virtual Overloading #862
Conversation
@MaxGraey How do I mark this as a draft? |
I'm afraid it could only be done while setting/open PR at first time |
Ah okay thanks I'll check that out next time. I've been using gitkraken to open the PR's so I'll switch to the github interface. |
be5d99e
to
e918e48
Compare
TODO: add better error messages
Still need to move logic into the interface methods.
Soon to add iterator
src/program.ts
Outdated
@@ -3408,6 +3438,9 @@ export class Class extends TypedElement { | |||
/** Tests if a value of this class type is assignable to a target of the specified class type. */ | |||
isAssignableTo(target: Class): bool { | |||
var current: Class | null = this; | |||
if (target.kind == ElementKind.INTERFACE) { | |||
return true; |
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 looks wrong?
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 because checking the interface requires resolving function prototypes. Which is why the check happens in the compiler method. This was an artifact as the condition in the compiler's method checks if the target is an interface so this never actually gets triggered. That is my least favorite part of this solution since it should happen in this method.
addImplementer(_class: Class): void { | ||
this.implementers.add(_class); | ||
if (this.base != null) { | ||
(<Class>this.base).addImplementer(_class); |
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 if base is null, should that maybe hit an assertion?
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.
A class on interface that doesn't extend anything has a base that is null. So it's the "base case" in the recursion. Should we instead make an Object class the default ?
iDecl.typeParameters = cDecl.typeParameters; | ||
iDecl.extendsType = cDecl.extendsType; | ||
iDecl.implementsTypes = cDecl.implementsTypes; | ||
iDecl.members = cDecl.members; |
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.
Seems like there's more to this than these properties, like the source range
src/program.ts
Outdated
typeArguments: Type[] = [], | ||
base: Interface | null = null | ||
typeArguments: Type[] | null = [], | ||
base: Interface | Class | null = null // interface can extend classes in typescript |
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.
There are no union types when compiling this as AS
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.
Yeah it should just be class.
src/util/collections.ts
Outdated
|
||
export function notNull<T>(t: T): bool { | ||
return t != null; | ||
} |
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.
Not a fan of these, as it's trading convenience for the overhead of indirect calls. Would prefer to inline.
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.
Yeah I never end up using these, did at first for the convenience but removed most used of iterators after first batch of feedback.
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.
Yeah I never ended up using these after removing most of my use of iterations in my first iteration. I'll remove them.
src/compiler.ts
Outdated
// this.error( | ||
// DiagnosticCode.Operation_not_supported, | ||
// declaration.range | ||
// ); |
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.
Is there missing something here?
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 this could be used to merge multiple interface declarations.
DiagnosticCode.Type_0_is_not_assignable_to_type_1, | ||
reportNode.range, | ||
fromType.toString(), | ||
toType.toString()); |
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.
Indentation
@@ -9217,12 +9280,394 @@ export class Compiler extends DiagnosticEmitter { | |||
return module.block(label, conditions, NativeType.I32); | |||
} | |||
|
|||
checkInterfaceImplementation(toType: Type, fromType: Type, reportNode: Node): bool { | |||
const _interface = (<Interface>toType.classReference!); | |||
const _class = fromType.classReference!; |
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.
Looks like these should be assert
calls
DiagnosticCode.Type_0_is_not_assignable_to_type_1, | ||
(<DeclaredElement>mem).declaration.range, | ||
mem.name, | ||
name); |
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.
Indentation; also looks like the error won't be very useful as it doesn't tell what's actually wrong?
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 just went off the compiler errors I got from typescript. In fact this should result in a parsing error, so I'll look into that.
name); | ||
continue; | ||
} | ||
// Error |
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.
Is there something missing here?
src/compiler.ts
Outdated
mem = (<Field>mem).prototype; | ||
imem = (<Property>imem).prototype; | ||
} | ||
case ElementKind.FIELD_PROTOTYPE: { |
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.
Mixing prototypes and instances here seems odd, like if it's missing a distinction of static vs instance.
src/compiler.ts
Outdated
} | ||
incorrectMember = false; | ||
} | ||
error = error || incorrectMember;// case where contiune skips the last check. |
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.
Spelling
src/compiler.ts
Outdated
_class.identifierNode.range, | ||
fromType.toString(), | ||
toType.toString() | ||
); |
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.
Indentation
relooper.addBranchForSwitch(first, returnBlock, classIds); | ||
} | ||
|
||
// finish relooper and prepare body of function |
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.
Wondering if the relooper will potentially build huge br_table
s here, for instance when dealing with ids 1 to 1024 - do we get 1024 cases? Other code intentionally generates sequences of br_if
s so Binaryen can decide if it's worth to make a br_table
or leave these as is depending on optimize and shrink levels.
Overall this appears somewhat rushed to me, with various minor problems, some oversights and missing comments to understand why it's built exactly this way. Don't get me wrong please, I appreciate your efforts, but I have a feeling that getting this right will be hard. |
Fails interface-fail
@final
decorator to prevent virtual method overloading.handle interfaces that extend classesNot this PR