From 92191dc1e10504d00cb08edb9a155123885b8841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=98=A4=EB=B3=91=EC=A7=84?= <64676070+sunrabbit123@users.noreply.github.com> Date: Sun, 13 Aug 2023 22:54:53 +0900 Subject: [PATCH] feat: Support more `keyof` for `IndexedAccessType`s (#1065) **Description:** ```ts function f90(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K]) { x1 = x2; x1 = x3; x2 = x1; x2 = x3; x3 = x1; x3 = x2; x1.length; x2.length; x3.length; } ``` --- .../src/analyzer/types/keyof.rs | 5 +- .../src/analyzer/types/mod.rs | 67 ++++++++++++++----- .../tests/tsc/types/nonPrimitive/.1.ts | 9 +++ .../keyofAndIndexedAccess.error-diff.json | 11 +-- .../keyofAndIndexedAccess.stats.rust-debug | 2 +- ...onstraintOfIndexAccessType.error-diff.json | 5 +- ...nstraintOfIndexAccessType.stats.rust-debug | 4 +- .../tests/tsc-stats.rust-debug | 7 +- 8 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 crates/stc_ts_file_analyzer/tests/tsc/types/nonPrimitive/.1.ts diff --git a/crates/stc_ts_file_analyzer/src/analyzer/types/keyof.rs b/crates/stc_ts_file_analyzer/src/analyzer/types/keyof.rs index c8d610e165..b1892bac52 100644 --- a/crates/stc_ts_file_analyzer/src/analyzer/types/keyof.rs +++ b/crates/stc_ts_file_analyzer/src/analyzer/types/keyof.rs @@ -5,8 +5,8 @@ use stc_ts_ast_rnode::{RIdent, RNumber, RStr, RTsEntityName, RTsLit}; use stc_ts_errors::{debug::force_dump_type_as_string, DebugExt, ErrorKind}; use stc_ts_type_ops::{is_str_lit_or_union, Fix}; use stc_ts_types::{ - Class, ClassMember, ClassProperty, Index, KeywordType, KeywordTypeMetadata, LitType, Method, MethodSignature, PropertySignature, Ref, - Type, TypeElement, Union, + Class, ClassMember, ClassProperty, Index, KeywordType, KeywordTypeMetadata, LitType, Method, MethodSignature, PropertySignature, + Readonly, Ref, Type, TypeElement, Union, }; use stc_utils::{cache::Freeze, ext::TypeVecExt, stack, try_cache}; use swc_atoms::js_word; @@ -67,6 +67,7 @@ impl Analyzer<'_, '_> { } match ty.normalize() { + Type::Readonly(Readonly { ty, .. }) => return self.keyof(span, ty), Type::Lit(ty) => { return self .keyof( diff --git a/crates/stc_ts_file_analyzer/src/analyzer/types/mod.rs b/crates/stc_ts_file_analyzer/src/analyzer/types/mod.rs index 90dba21dcf..119bbe5f6e 100644 --- a/crates/stc_ts_file_analyzer/src/analyzer/types/mod.rs +++ b/crates/stc_ts_file_analyzer/src/analyzer/types/mod.rs @@ -555,23 +555,56 @@ impl Analyzer<'_, '_> { disallow_unknown_object_property: true, ..self.ctx }; - let prop_ty = self.with_ctx(ctx).access_property( - actual_span, - &obj_ty, - &Key::Computed(ComputedKey { - span: actual_span, - expr: Box::new(RExpr::Invalid(RInvalid { span: actual_span })), - ty: index_ty.clone(), - }), - TypeOfMode::RValue, - IdCtx::Type, - AccessPropertyOpts { - disallow_creating_indexed_type_from_ty_els: true, - disallow_inexact: true, - do_not_use_any_for_object: true, - ..Default::default() - }, - ); + let prop_ty = { + let type_mode = if ctx.in_fn_with_return_type { + TypeOfMode::LValue + } else { + TypeOfMode::RValue + }; + + let mut result = self.with_ctx(ctx).access_property( + actual_span, + &obj_ty, + &Key::Computed(ComputedKey { + span: actual_span, + expr: Box::new(RExpr::Invalid(RInvalid { span: actual_span })), + ty: index_ty.clone(), + }), + type_mode, + IdCtx::Type, + AccessPropertyOpts { + disallow_creating_indexed_type_from_ty_els: true, + disallow_inexact: true, + do_not_use_any_for_object: true, + ..Default::default() + }, + ); + + if result.is_err() { + if let Type::Param(TypeParam { constraint: Some(ty), .. }) = index_ty.normalize() { + let prop = self.normalize(span, Cow::Borrowed(ty), opts)?.into_owned(); + result = self.with_ctx(ctx).access_property( + actual_span, + &obj_ty, + &Key::Computed(ComputedKey { + span: actual_span, + expr: Box::new(RExpr::Invalid(RInvalid { span: actual_span })), + ty: Box::new(prop), + }), + type_mode, + IdCtx::Type, + AccessPropertyOpts { + disallow_creating_indexed_type_from_ty_els: true, + disallow_inexact: true, + do_not_use_any_for_object: true, + ..Default::default() + }, + ); + } + } + + result + }; if let Ok(prop_ty) = prop_ty { if ty.type_eq(&prop_ty) { diff --git a/crates/stc_ts_file_analyzer/tests/tsc/types/nonPrimitive/.1.ts b/crates/stc_ts_file_analyzer/tests/tsc/types/nonPrimitive/.1.ts new file mode 100644 index 0000000000..37063f079b --- /dev/null +++ b/crates/stc_ts_file_analyzer/tests/tsc/types/nonPrimitive/.1.ts @@ -0,0 +1,9 @@ +// @strict: true + + +function l(s: string, tp: T[P]): void { + tp = s; +} +function m(s: string, tp: T[P]): void { + tp = s; +} \ No newline at end of file diff --git a/crates/stc_ts_type_checker/tests/conformance/types/keyof/keyofAndIndexedAccess.error-diff.json b/crates/stc_ts_type_checker/tests/conformance/types/keyof/keyofAndIndexedAccess.error-diff.json index 724ce11a8a..62061f3494 100644 --- a/crates/stc_ts_type_checker/tests/conformance/types/keyof/keyofAndIndexedAccess.error-diff.json +++ b/crates/stc_ts_type_checker/tests/conformance/types/keyof/keyofAndIndexedAccess.error-diff.json @@ -4,7 +4,8 @@ "extra_errors": { "TS2345": 8, "TS2339": 2, - "TS2322": 12 + "TS0": 2, + "TS2322": 8 }, "extra_error_lines": { "TS2345": [ @@ -21,11 +22,11 @@ 147, 152 ], + "TS0": [ + 286, + 338 + ], "TS2322": [ - 307, - 309, - 310, - 311, 326, 327, 328, diff --git a/crates/stc_ts_type_checker/tests/conformance/types/keyof/keyofAndIndexedAccess.stats.rust-debug b/crates/stc_ts_type_checker/tests/conformance/types/keyof/keyofAndIndexedAccess.stats.rust-debug index 4f0736a120..93c216b79c 100644 --- a/crates/stc_ts_type_checker/tests/conformance/types/keyof/keyofAndIndexedAccess.stats.rust-debug +++ b/crates/stc_ts_type_checker/tests/conformance/types/keyof/keyofAndIndexedAccess.stats.rust-debug @@ -1,6 +1,6 @@ Stats { required_error: 0, matched_error: 5, - extra_error: 22, + extra_error: 20, panic: 0, } \ No newline at end of file diff --git a/crates/stc_ts_type_checker/tests/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.error-diff.json b/crates/stc_ts_type_checker/tests/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.error-diff.json index 3e392f20b1..f8c3529e5f 100644 --- a/crates/stc_ts_type_checker/tests/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.error-diff.json +++ b/crates/stc_ts_type_checker/tests/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.error-diff.json @@ -1,10 +1,11 @@ { "required_errors": { - "TS2322": 1 + "TS2322": 2 }, "required_error_lines": { "TS2322": [ - 22 + 25, + 28 ] }, "extra_errors": {}, diff --git a/crates/stc_ts_type_checker/tests/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.stats.rust-debug b/crates/stc_ts_type_checker/tests/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.stats.rust-debug index 4074730ba8..13ac66ffd7 100644 --- a/crates/stc_ts_type_checker/tests/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.stats.rust-debug +++ b/crates/stc_ts_type_checker/tests/conformance/types/nonPrimitive/nonPrimitiveConstraintOfIndexAccessType.stats.rust-debug @@ -1,6 +1,6 @@ Stats { - required_error: 1, - matched_error: 9, + required_error: 2, + matched_error: 8, extra_error: 0, panic: 0, } \ No newline at end of file diff --git a/crates/stc_ts_type_checker/tests/tsc-stats.rust-debug b/crates/stc_ts_type_checker/tests/tsc-stats.rust-debug index 8cf4fbce6a..9a3b700764 100644 --- a/crates/stc_ts_type_checker/tests/tsc-stats.rust-debug +++ b/crates/stc_ts_type_checker/tests/tsc-stats.rust-debug @@ -1,6 +1,5 @@ Stats { - required_error: 3501, - matched_error: 6534, - extra_error: 766, - panic: 73, + required_error: 3502, + matched_error: 6533, + extra_error: 764, } \ No newline at end of file