From 969204e7743db8eb02f938f73a7040b07c033e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 9 Feb 2023 16:59:15 +0900 Subject: [PATCH 1/6] Enable --- .../visualize/exprs/assign/typeNarrowing/{.seq-1.ts => seq-1.ts} | 0 .../exprs/assign/typeNarrowing/{.simple-1.ts => simple-1.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/{.seq-1.ts => seq-1.ts} (100%) rename crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/{.simple-1.ts => simple-1.ts} (100%) diff --git a/crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/.seq-1.ts b/crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/seq-1.ts similarity index 100% rename from crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/.seq-1.ts rename to crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/seq-1.ts diff --git a/crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/.simple-1.ts b/crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/simple-1.ts similarity index 100% rename from crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/.simple-1.ts rename to crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/simple-1.ts From c316b2c7bf8292874284df7c97226b7102ead102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 9 Feb 2023 17:02:23 +0900 Subject: [PATCH 2/6] Move to pass-only tests --- .../exprs/assign => pass-only}/typeNarrowing/seq-1.ts | 2 +- .../exprs/assign => pass-only}/typeNarrowing/simple-1.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename crates/stc_ts_file_analyzer/tests/{visualize/exprs/assign => pass-only}/typeNarrowing/seq-1.ts (78%) rename crates/stc_ts_file_analyzer/tests/{visualize/exprs/assign => pass-only}/typeNarrowing/simple-1.ts (77%) diff --git a/crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/seq-1.ts b/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/seq-1.ts similarity index 78% rename from crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/seq-1.ts rename to crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/seq-1.ts index 2d617ddcb3..ebafceac9c 100644 --- a/crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/seq-1.ts +++ b/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/seq-1.ts @@ -3,6 +3,6 @@ let obj: any; x = true; (x = "", obj).foo = (x = x.length); -x; // number +x.toExponential(); // number export { } \ No newline at end of file diff --git a/crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/simple-1.ts b/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/simple-1.ts similarity index 77% rename from crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/simple-1.ts rename to crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/simple-1.ts index c2dbe745db..5a70bea394 100644 --- a/crates/stc_ts_file_analyzer/tests/visualize/exprs/assign/typeNarrowing/simple-1.ts +++ b/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/simple-1.ts @@ -4,4 +4,4 @@ do { x; // number x = ""; } while (x = x.length) -x; // number \ No newline at end of file +x.toExponential(); // number \ No newline at end of file From 4835626e55d403d3aed2dbfdea83b6d02b6756f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 9 Feb 2023 17:14:22 +0900 Subject: [PATCH 3/6] `assertNumber` --- .../tests/pass-only/typeNarrowing/seq-1.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/seq-1.ts b/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/seq-1.ts index ebafceac9c..f11282cf51 100644 --- a/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/seq-1.ts +++ b/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/seq-1.ts @@ -3,6 +3,8 @@ let obj: any; x = true; (x = "", obj).foo = (x = x.length); -x.toExponential(); // number + +declare function assertNumber(n: number): void; +assertNumber(x) export { } \ No newline at end of file From 905447dc83c84b3aaf430de12454e2a04e5726c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 9 Feb 2023 17:14:31 +0900 Subject: [PATCH 4/6] fixup --- .../tests/pass-only/typeNarrowing/simple-1.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/simple-1.ts b/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/simple-1.ts index 5a70bea394..f7b3466da0 100644 --- a/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/simple-1.ts +++ b/crates/stc_ts_file_analyzer/tests/pass-only/typeNarrowing/simple-1.ts @@ -4,4 +4,5 @@ do { x; // number x = ""; } while (x = x.length) -x.toExponential(); // number \ No newline at end of file +declare function assertNumber(n: number): void; +assertNumber(x) \ No newline at end of file From 525f86f429e57e1da1396ef42da69fbb72b8ce60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 9 Feb 2023 17:18:52 +0900 Subject: [PATCH 5/6] LoopKind --- .../src/analyzer/stmt/loops.rs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/stc_ts_file_analyzer/src/analyzer/stmt/loops.rs b/crates/stc_ts_file_analyzer/src/analyzer/stmt/loops.rs index cf0c5ff31e..bcd30d71fd 100644 --- a/crates/stc_ts_file_analyzer/src/analyzer/stmt/loops.rs +++ b/crates/stc_ts_file_analyzer/src/analyzer/stmt/loops.rs @@ -27,12 +27,20 @@ enum ForHeadKind { Of { is_awaited: bool }, } +#[derive(Debug, Clone, Copy)] +enum LoopKind { + While, + DoWhile, + ForIn, + ForOf { is_awaited: bool }, +} + impl Analyzer<'_, '_> { /// We evaluate loop bodies multiple time. /// But actually we don't report errors /// /// If type does not change due to a loop, we evaluate - fn validate_loop_body_with_scope(&mut self, test: Option<&RExpr>, body: &RStmt) -> VResult<()> { + fn validate_loop_body_with_scope(&mut self, test: Option<&RExpr>, body: &RStmt, kind: LoopKind) -> VResult<()> { let mut orig_facts = self.cur_facts.take(); let mut prev_facts = orig_facts.true_facts.take(); @@ -373,7 +381,16 @@ impl Analyzer<'_, '_> { child.validate_lhs_of_for_loop(left, &elem_ty, kind); - child.validate_loop_body_with_scope(None, body).report(&mut child.storage); + child + .validate_loop_body_with_scope( + None, + body, + match kind { + ForHeadKind::Of { is_awaited } => LoopKind::ForOf { is_awaited }, + ForHeadKind::In => LoopKind::ForIn, + }, + ) + .report(&mut child.storage); Ok(()) })?; @@ -409,7 +426,7 @@ impl Analyzer<'_, '_> { #[validator] impl Analyzer<'_, '_> { fn validate(&mut self, node: &RWhileStmt) { - self.validate_loop_body_with_scope(Some(&node.test), &node.body) + self.validate_loop_body_with_scope(Some(&node.test), &node.body, LoopKind::While) .report(&mut self.storage); Ok(()) @@ -421,7 +438,7 @@ impl Analyzer<'_, '_> { fn validate(&mut self, node: &RDoWhileStmt) { node.body.visit_with(self); - self.validate_loop_body_with_scope(Some(&node.test), &node.body) + self.validate_loop_body_with_scope(Some(&node.test), &node.body, LoopKind::DoWhile) .report(&mut self.storage); Ok(()) From f75a87fce8323fbff84fcecb81bcd2ad0e9179f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 9 Feb 2023 17:40:23 +0900 Subject: [PATCH 6/6] Split facts --- .../src/analyzer/stmt/loops.rs | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/crates/stc_ts_file_analyzer/src/analyzer/stmt/loops.rs b/crates/stc_ts_file_analyzer/src/analyzer/stmt/loops.rs index bcd30d71fd..287b75d93c 100644 --- a/crates/stc_ts_file_analyzer/src/analyzer/stmt/loops.rs +++ b/crates/stc_ts_file_analyzer/src/analyzer/stmt/loops.rs @@ -50,10 +50,8 @@ impl Analyzer<'_, '_> { let mut orig_vars = Some(self.scope.vars.clone()); loop { - let mut facts_from_body: CondFacts = self.with_child_with_hook( - ScopeKind::LoopBody { last }, - prev_facts.clone(), - |child: &mut Analyzer| { + let facts_from_cond: CondFacts = + self.with_child(ScopeKind::LoopBody { last }, prev_facts.clone(), |child: &mut Analyzer| { child.ctx.ignore_errors |= !last; { @@ -64,6 +62,18 @@ impl Analyzer<'_, '_> { test.visit_with(&mut *child.with_ctx(ctx)); } + Ok(child.cur_facts.true_facts.take()) + })?; + + let mut facts_for_body = prev_facts.clone(); + facts_for_body += facts_from_cond.clone(); + + let mut facts_from_body: CondFacts = self.with_child_with_hook( + ScopeKind::LoopBody { last }, + facts_from_cond.clone(), + |child: &mut Analyzer| { + child.ctx.ignore_errors |= !last; + body.visit_with(child); Ok(child.cur_facts.true_facts.take()) @@ -78,7 +88,22 @@ impl Analyzer<'_, '_> { facts_from_body.excludes.clear(); if last { - prev_facts += facts_from_body; + match kind { + LoopKind::DoWhile => { + prev_facts += facts_from_body; + prev_facts += facts_from_cond; + } + + LoopKind::While => { + prev_facts += facts_from_cond; + prev_facts += facts_from_body; + } + + _ => { + prev_facts += facts_from_body; + } + } + break; }