-
-
Notifications
You must be signed in to change notification settings - Fork 669
feat: add type narrow to support better type check #2352
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
feat: add type narrow to support better type check #2352
Conversation
1795f6f
to
df38498
Compare
When I thought about narrowing in the past, the mechanism I had in mind was to add a new |
I have not found |
By the way, we should not support narrow type for variant like class A {}
class B extends A {
foo(): void {}
}
class C {
v: A = new A();
}
let c = new C();
let d = c;
c.v = new B();
if (c.v instanceof B) {
d.v = new A(); // c.v has changed, but compiler don't know
c.v.foo();
} |
This reverts commit df38498.
d.v = new A(); // c.v has changed, but compiler don't know well. that's problem on TS. I guess they are fixed this later. I see no reason to refuse it if we can handle this case correctly |
Quite similar to why nullability checks are limited to locals. Also applies to narrowing if we don't want to run into unsoundness. ...
let cv = c.v;
if (cv instanceof B) {
// works
} |
…t/add-type-narrow
Btw such flow mechanics is quite typical: var thenFlow = flow.fork();
this.currentFlow = thenFlow;
thenFlow.inheritNarrowedTypeIfTrue(condExpr); I'm wondering could we add some method for Flow which include this routine? class Flow {
...
toBranch(condExpr: Expression, ifTrue: bool): Flow {
var other = this.fork();
if (ifTrue) {
other.inheritNarrowedTypeIfTrue(condExpr);
} else {
other.inheritNarrowedTypeIfFalse(condExpr);
}
return other;
}
} And later simplify to: this.currentFlow = flow.toBranch(condExpr, true); Not sure about naming. Probably you could call all of this better |
@dcodeIO Could this feature merge? |
@@ -2994,6 +2991,8 @@ export class Compiler extends DiagnosticEmitter { | |||
); | |||
pendingElements.delete(dummy); | |||
flow.freeScopedDummyLocal(name); | |||
|
|||
initType = this.currentType; |
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.
Due to compiling with Constraincts.CONV_IMPLICIT
, I think initType
is always the same as type
here. Sure that the additional initType
variable is needed?
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.
consider this testcase. Actually initType
and type
are not always the same in nullable
export function testInit(a: Ref): void {
let c: Ref | null = requireNonNull(a);
if (isNullable(c)) ERROR("should be non-nullable");
}
@dcodeIO Could you kindly review this PR? |
I'm having a hard time reviewing the PR, and would like to suggest to split it up a little. As a start, there has been the refactoring from From there on it gets a little tricky, as I am not confident about having an out-of-line |
Yes, I will split it into several PR. But it needs some time because I am preparing my graduation thesis now😄 |
No description provided.