diff --git a/Cargo.lock b/Cargo.lock index 057da0195..18abc0270 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,9 +57,9 @@ checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "ast_node" -version = "0.9.6" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e3e06ec6ac7d893a0db7127d91063ad7d9da8988f8a1a256f03729e6eec026" +checksum = "2ab31376d309dd3bfc9cfb3c11c93ce0e0741bbe0354b20e7f8c60b044730b79" dependencies = [ "proc-macro2", "quote", @@ -279,9 +279,7 @@ dependencies = [ [[package]] name = "deno_ast" -version = "0.38.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2417aad5382d10d035e46d35f2f5fbbb93a922816408245ee585e7ca775194" +version = "0.38.2" dependencies = [ "anyhow", "base64 0.21.7", @@ -512,9 +510,9 @@ dependencies = [ [[package]] name = "from_variant" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a0b11eeb173ce52f84ebd943d42e58813a2ebb78a6a3ff0a243b71c5199cd7b" +checksum = "fdc9cc75639b041067353b9bce2450d6847e547276c6fbe4487d7407980e07db" dependencies = [ "proc-macro2", "swc_macros_common", @@ -1432,9 +1430,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "indexmap", "itoa", @@ -1579,9 +1577,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_enum" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b650ea2087d32854a0f20b837fc56ec987a1cb4f758c9757e1171ee9812da63" +checksum = "05e383308aebc257e7d7920224fa055c632478d92744eca77f99be8fa1545b90" dependencies = [ "proc-macro2", "quote", @@ -1623,9 +1621,9 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.33.25" +version = "0.33.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a529796c240cd87da18d26d63f9de4c7ad3680cf0a04b95f0c37f4c4f0a0da63" +checksum = "a2f9706038906e66f3919028f9f7a37f3ed552f1b85578e93f4468742e2da438" dependencies = [ "ast_node", "better_scoped_tls", @@ -1649,9 +1647,9 @@ dependencies = [ [[package]] name = "swc_config" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ada712ac5e28a301683c8af957e8a56deca675cbc376473dd207a527b989efb5" +checksum = "7be1a689e146be1eae53139482cb061dcf0fa01dff296bbe7b96fff92d8e2936" dependencies = [ "anyhow", "indexmap", @@ -1663,9 +1661,9 @@ dependencies = [ [[package]] name = "swc_config_macro" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2574f75082322a27d990116cd2a24de52945fc94172b24ca0b3e9e2a6ceb6b" +checksum = "7c5f56139042c1a95b54f5ca48baa0e0172d369bcc9d3d473dad1de36bae8399" dependencies = [ "proc-macro2", "quote", @@ -1675,9 +1673,9 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "0.113.0" +version = "0.113.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f99fdda741656887f4cf75c1cee249a5f0374d67d30acc2b073182e902546ff2" +checksum = "dc1690cc0c9ab60b44ac0225ba1e231ac532f7ba1d754df761c6ee607561afae" dependencies = [ "bitflags 2.5.0", "is-macro", @@ -1693,9 +1691,9 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "0.149.0" +version = "0.149.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c21b8ae99bc3b95c6f7909915cd1e5994bec4e5b576f2e2a6879e56f2770760" +checksum = "4fef147127a2926ca26171c7afcbf028ff86dc543ced87d316713f25620a15b9" dependencies = [ "memchr", "num-bigint", @@ -1712,9 +1710,9 @@ dependencies = [ [[package]] name = "swc_ecma_codegen_macros" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ab87ba81ae05efd394ab4a8cbdba595ac3554a5e393c76699449d47c43582e" +checksum = "090e409af49c8d1a3c13b3aab1ed09dd4eda982207eb3e63c2ad342f072b49c8" dependencies = [ "proc-macro2", "quote", @@ -1724,9 +1722,9 @@ dependencies = [ [[package]] name = "swc_ecma_loader" -version = "0.45.27" +version = "0.45.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a923880fc27cf5f3d2a684debb7c5a0ee60100af1bfe424cb5e722d290bf88a" +checksum = "92c68f934bd2c51f29c4ad0bcae09924e9dc30d7ce0680367d45b42d40338a67" dependencies = [ "anyhow", "pathdiff", @@ -1738,9 +1736,9 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.144.0" +version = "0.144.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da9f3a58f0a64410f4006eb1fdb64d190ad3cc6cd12a7bf1f0dbb916e4ca4c7" +checksum = "0499e69683ae5d67a20ff0279b94bc90f29df7922a46331b54d5dd367bf89570" dependencies = [ "either", "new_debug_unreachable", @@ -1760,9 +1758,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "0.138.0" +version = "0.138.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91771e358664649cf2cabec86a270bd9ce267f5213f299cacb255951b5edf06b" +checksum = "eddb95c2bdad1c9c29edf35712e1e0f9b9ddc1cdb5ba2d582fd93468cb075a03" dependencies = [ "better_scoped_tls", "bitflags 2.5.0", @@ -1783,9 +1781,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.127.0" +version = "0.127.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa5cd60314f35a114dc85955c6b645e9bb13fdfda4f732137ed62a482ca8990" +checksum = "53043d81678f3c693604eeb1d1f0fe6ba10f303104a31b954dbeebed9cadf530" dependencies = [ "swc_atoms", "swc_common", @@ -1797,9 +1795,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_macros" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e309b88f337da54ef7fe4c5b99c2c522927071f797ee6c9fb8b6bf2d100481" +checksum = "500a1dadad1e0e41e417d633b3d6d5de677c9e0d3159b94ba3348436cdb15aab" dependencies = [ "proc-macro2", "quote", @@ -1809,9 +1807,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.172.0" +version = "0.172.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "067a79cba791af32fb0634c0ca08051e47b56ccfe8d07349b7787b22da401084" +checksum = "7fbc414d6a9c5479cfb4c6e92fcdac504582bd7bc89a0ed7f8808b72dc8bd1f0" dependencies = [ "either", "rustc-hash", @@ -1829,9 +1827,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.184.0" +version = "0.184.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69c87599f4a10987fe2687967e5448858b458f2924faa62f044acd56f4e3ffda" +checksum = "565a76c4ca47ce31d78301c0beab878e4c2cb4f624691254d834ec8c0e236755" dependencies = [ "base64 0.21.7", "dashmap", @@ -1853,9 +1851,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "0.189.0" +version = "0.189.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ea0dc9076708448e8ded8e1119717e0e6e095b1ba42b4c8d7fdb1d26fba418" +checksum = "e209026c1d3c577cafac257d87e7c0d23119282fbdc8ed03d7f56077e95beb90" dependencies = [ "ryu-js", "serde", @@ -1870,9 +1868,9 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.128.0" +version = "0.128.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd533f5751b7a8673bd843151c4e6e64a2dcf6c1f65331401e88f244c0e85de7" +checksum = "fe5242670bc74e0a0b64b9d4912b37be36944517ce0881314162aeb4381272c3" dependencies = [ "indexmap", "num_cpus", @@ -1888,9 +1886,9 @@ dependencies = [ [[package]] name = "swc_ecma_visit" -version = "0.99.0" +version = "0.99.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c74008ebc5e0d3d9a1b3df54083ddbff1a375cfadff857da1fdc7837b48c52d" +checksum = "28a6ce28ad8e591f8d627f1f9cb26b25e5d83052a9bc1b674d95fc28040cfa98" dependencies = [ "num-bigint", "swc_atoms", @@ -1913,9 +1911,9 @@ dependencies = [ [[package]] name = "swc_macros_common" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5be7766a95a2840ded618baeaab63809b71230ef19094b34f76c8af4d85aa2" +checksum = "91745f3561057493d2da768437c427c0e979dff7396507ae02f16c981c4a8466" dependencies = [ "proc-macro2", "quote", @@ -1924,9 +1922,9 @@ dependencies = [ [[package]] name = "swc_visit" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0263be55289abfe9c877ffef83d877b5bdfac036ffe2de793f48f5e47e41dbae" +checksum = "043d11fe683dcb934583ead49405c0896a5af5face522e4682c16971ef7871b9" dependencies = [ "either", "swc_visit_macros", @@ -1934,9 +1932,9 @@ dependencies = [ [[package]] name = "swc_visit_macros" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33fc817055fe127b4285dc85058596768bfde7537ae37da82c67815557f03e33" +checksum = "4ae9ef18ff8daffa999f729db056d2821cd2f790f3a11e46422d19f46bb193e7" dependencies = [ "Inflector", "proc-macro2", @@ -2199,9 +2197,9 @@ checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f" [[package]] name = "unicode-id-start" -version = "1.1.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f73150333cb58412db36f2aca8f2875b013049705cc77b94ded70a1ab1f5da" +checksum = "02aebfa694eccbbbffdd92922c7de136b9fe764396d2f10e21bce1681477cfc1" [[package]] name = "unicode-ident" diff --git a/Cargo.toml b/Cargo.toml index a4a4913a9..3af54f594 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,3 +73,6 @@ codegen-units = 1 incremental = true lto = true opt-level = "z" + +[patch.crates-io] +deno_ast = { path = "/mnt/artemis/Projects/github.com/denoland/deno_ast" } \ No newline at end of file diff --git a/src/fast_check/mod.rs b/src/fast_check/mod.rs index 9b1cc3e1b..50d9ea5e9 100644 --- a/src/fast_check/mod.rs +++ b/src/fast_check/mod.rs @@ -25,6 +25,7 @@ mod swc_helpers; mod transform; #[cfg(feature = "fast_check")] mod transform_dts; +mod type_infer; pub use cache::FastCheckCache; pub use cache::FastCheckCacheItem; @@ -39,6 +40,9 @@ pub use transform::FastCheckModule; #[cfg(feature = "fast_check")] pub use transform::TransformOptions; +use self::type_infer::ExprInferFailCause; +use self::type_infer::ReturnTypeInferFailCause; + #[derive(Clone)] pub struct FastCheckDiagnosticRange { pub specifier: ModuleSpecifier, @@ -46,6 +50,15 @@ pub struct FastCheckDiagnosticRange { pub text_info: SourceTextInfo, } +impl FastCheckDiagnosticRange { + fn into_diagnostic_range(&self) -> DiagnosticSourceRange { + DiagnosticSourceRange { + start: DiagnosticSourcePos::SourcePos(self.range.start), + end: DiagnosticSourcePos::SourcePos(self.range.end), + } + } +} + impl std::fmt::Debug for FastCheckDiagnosticRange { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("FastCheckDiagnosticRange") @@ -84,11 +97,15 @@ pub enum FastCheckDiagnostic { }, #[error("missing explicit type in the public API")] MissingExplicitType { range: FastCheckDiagnosticRange }, - #[error("missing explicit return type in the public API")] - MissingExplicitReturnType { - range: FastCheckDiagnosticRange, - is_definitely_void_or_never: bool, - is_async: bool, + #[error("unknown type for variable in the public API")] + UnknownVarType { + ident: FastCheckDiagnosticRange, + cause: Option>, + }, + #[error("unknown return type for function in the public API")] + UnknownReturnType { + ident: FastCheckDiagnosticRange, + cause: Option>, }, #[error( "found an ambient module, which is a global augmentation, which are not unsupported" @@ -158,51 +175,14 @@ pub enum FastCheckDiagnostic { Cached { specifier: ModuleSpecifier }, } -impl FastCheckDiagnostic { - /// Return a human readable description of what the range of the diagnostic - /// is. - /// - /// Panics if the diagnostic does not have a range. - pub fn range_description(&self) -> Option<&'static str> { - use FastCheckDiagnostic::*; - match self { - NotFoundReference { .. } => Some("this is the reference"), - MissingExplicitType { .. } => { - Some("this symbol is missing an explicit type") - } - MissingExplicitReturnType { .. } => { - Some("this function is missing an explicit return type") - } - UnsupportedAmbientModule { .. } => None, - UnsupportedComplexReference { .. } => Some("this is the reference"), - UnsupportedDefaultExportExpr { .. } => None, - UnsupportedDestructuring { .. } => None, - UnsupportedExpandoProperty { .. } => None, - UnsupportedGlobalModule { .. } => None, - UnsupportedRequire { .. } => None, - UnsupportedPrivateMemberReference { .. } => Some("this is the reference"), - UnsupportedSuperClassExpr { .. } => { - Some("this is the superclass expression") - } - UnsupportedTsExportAssignment { .. } => None, - UnsupportedTsNamespaceExport { .. } => None, - UnsupportedUsing { .. } => None, - UnsupportedNestedJavaScript { .. } => None, - UnsupportedJavaScriptEntrypoint { .. } => None, - Emit { .. } => None, - ExportNotFound { .. } => None, - Cached { .. } => None, - } - } -} - impl FastCheckDiagnostic { pub fn specifier(&self) -> &ModuleSpecifier { use FastCheckDiagnostic::*; match self { NotFoundReference { range, .. } => &range.specifier, - MissingExplicitType { range } => &range.specifier, - MissingExplicitReturnType { range, .. } => &range.specifier, + MissingExplicitType { range, .. } => &range.specifier, + UnknownVarType { ident, .. } => &ident.specifier, + UnknownReturnType { ident, .. } => &ident.specifier, UnsupportedAmbientModule { range } => &range.specifier, UnsupportedComplexReference { range, .. } => &range.specifier, UnsupportedDefaultExportExpr { range } => &range.specifier, @@ -227,8 +207,9 @@ impl FastCheckDiagnostic { use FastCheckDiagnostic::*; match self { NotFoundReference { range, .. } => Some(range), - MissingExplicitType { range } => Some(range), - MissingExplicitReturnType { range, .. } => Some(range), + MissingExplicitType { range, .. } => Some(range), + UnknownVarType { ident, .. } => Some(ident), + UnknownReturnType { ident: range, .. } => Some(range), UnsupportedAmbientModule { range } => Some(range), UnsupportedComplexReference { range, .. } => Some(range), UnsupportedDefaultExportExpr { range } => Some(range), @@ -256,7 +237,8 @@ impl deno_ast::diagnostics::Diagnostic for FastCheckDiagnostic { match self { NotFoundReference { .. } | MissingExplicitType { .. } - | MissingExplicitReturnType { .. } + | UnknownVarType { .. } + | UnknownReturnType { .. } | UnsupportedAmbientModule { .. } | UnsupportedComplexReference { .. } | UnsupportedDefaultExportExpr { .. } @@ -283,7 +265,8 @@ impl deno_ast::diagnostics::Diagnostic for FastCheckDiagnostic { Cow::Borrowed(match self { NotFoundReference { .. } => "not-found-reference", MissingExplicitType { .. } => "missing-explicit-type", - MissingExplicitReturnType { .. } => "missing-explicit-return-type", + UnknownVarType { .. } => "unknown-var-type", + UnknownReturnType { .. } => "unknown-return-type", UnsupportedAmbientModule { .. } => "unsupported-ambient-module", UnsupportedComplexReference { .. } => "unsupported-complex-reference", UnsupportedDefaultExportExpr { .. } => "unsupported-default-export-expr", @@ -327,18 +310,110 @@ impl deno_ast::diagnostics::Diagnostic for FastCheckDiagnostic { } } - fn snippet(&self) -> Option> { - self.range().map(|range| DiagnosticSnippet { - source: Cow::Borrowed(&range.text_info), - highlight: DiagnosticSnippetHighlight { - style: DiagnosticSnippetHighlightStyle::Error, - range: DiagnosticSourceRange { - start: DiagnosticSourcePos::SourcePos(range.range.start), - end: DiagnosticSourcePos::SourcePos(range.range.end), - }, - description: self.range_description().map(Cow::Borrowed), - }, - }) + fn snippet(&self) -> Option> { + fn simple<'a>( + range: &'a FastCheckDiagnosticRange, + description: Option<&'static str>, + ) -> DiagnosticSnippet<'a> { + DiagnosticSnippet { + source: Cow::Borrowed(&range.text_info), + highlights: vec![DiagnosticSnippetHighlight { + style: DiagnosticSnippetHighlightStyle::Error, + range: range.into_diagnostic_range(), + description: description.map(Cow::Borrowed), + }], + } + } + + match self { + FastCheckDiagnostic::NotFoundReference { range, .. } => { + Some(simple(range, Some("this is the reference"))) + } + FastCheckDiagnostic::MissingExplicitType { range } => Some(simple( + range, + Some("this symbol is missing an explicit type"), + )), + FastCheckDiagnostic::UnknownVarType { ident, cause } => { + if let Some(cause) = cause { + let mut highlights = vec![ + DiagnosticSnippetHighlight { + style: DiagnosticSnippetHighlightStyle::Error, + range: ident.into_diagnostic_range(), + description: Some(Cow::Borrowed("this variable's type could not be inferred because its initializer")), + }, + ]; + cause.highlights(&mut highlights); + + Some(DiagnosticSnippet { + source: Cow::Borrowed(&ident.text_info), + highlights, + }) + } else { + Some(simple( + ident, + Some("this variable is missing an explicit type"), + )) + } + } + FastCheckDiagnostic::UnknownReturnType { ident, cause } => { + if let Some(cause) = cause { + let mut highlights = vec![]; + cause.highlights(&mut highlights, ident, "this function", false); + Some(DiagnosticSnippet { + source: Cow::Borrowed(&ident.text_info), + highlights, + }) + } else { + Some(simple( + ident, + Some("this function is missing an explicit return type"), + )) + } + } + FastCheckDiagnostic::UnsupportedAmbientModule { range } => { + Some(simple(range, None)) + } + FastCheckDiagnostic::UnsupportedComplexReference { range, .. } => { + Some(simple(range, Some("this is the reference"))) + } + FastCheckDiagnostic::UnsupportedDefaultExportExpr { range } => { + Some(simple(range, None)) + } + FastCheckDiagnostic::UnsupportedDestructuring { range } => { + Some(simple(range, None)) + } + FastCheckDiagnostic::UnsupportedExpandoProperty { range, .. } => { + Some(simple(range, None)) + } + FastCheckDiagnostic::UnsupportedGlobalModule { range } => { + Some(simple(range, None)) + } + FastCheckDiagnostic::UnsupportedRequire { range } => { + Some(simple(range, None)) + } + FastCheckDiagnostic::UnsupportedPrivateMemberReference { + range, .. + } => Some(simple(range, Some("this is the reference"))), + FastCheckDiagnostic::UnsupportedSuperClassExpr { range } => { + Some(simple(range, Some("this is the superclass expression"))) + } + FastCheckDiagnostic::UnsupportedTsExportAssignment { range } => { + Some(simple(range, None)) + } + FastCheckDiagnostic::UnsupportedTsNamespaceExport { range } => { + Some(simple(range, None)) + } + FastCheckDiagnostic::UnsupportedUsing { range } => { + Some(simple(range, None)) + } + FastCheckDiagnostic::UnsupportedNestedJavaScript { .. } => None, + FastCheckDiagnostic::UnsupportedJavaScriptEntrypoint { .. } => None, + FastCheckDiagnostic::Emit { .. } => None, + FastCheckDiagnostic::ExportNotFound { .. } => None, + FastCheckDiagnostic::Cached { .. } => { + unreachable!("cached diagnostics should not be displayed") + } + } } fn hint(&self) -> Option> { @@ -350,11 +425,16 @@ impl deno_ast::diagnostics::Diagnostic for FastCheckDiagnostic { MissingExplicitType { .. } => { Cow::Borrowed("add an explicit type annotation to the symbol") } - MissingExplicitReturnType { is_definitely_void_or_never, is_async, .. } => { - if *is_definitely_void_or_never { - Cow::Borrowed("add an explicit return type of 'void' or 'never' to the function") - } else if *is_async { - Cow::Borrowed("add an explicit return type of 'Promise' or 'Promise' to the function") + UnknownVarType { cause, .. } => { + if let Some(hint) = cause.as_ref().and_then(|cause| cause.hint(" in the variable declaration initializer".into())) { + Cow::Owned(hint) + } else { + Cow::Borrowed("add an explicit type annotation to the variable declaration") + } + } + UnknownReturnType { cause, .. } => { + if let Some(hint) = cause.as_ref().and_then(|cause|cause.hint("function", "".into())) { + Cow::Owned(hint) } else { Cow::Borrowed("add an explicit return type to the function") } @@ -384,9 +464,7 @@ impl deno_ast::diagnostics::Diagnostic for FastCheckDiagnostic { }) } - fn snippet_fixed( - &self, - ) -> Option> { + fn snippet_fixed(&self) -> Option> { None } @@ -399,15 +477,21 @@ impl deno_ast::diagnostics::Diagnostic for FastCheckDiagnostic { MissingExplicitType { .. } => Cow::Borrowed(&[ Cow::Borrowed("all symbols in the public API must have an explicit type") ]), - MissingExplicitReturnType { is_definitely_void_or_never, is_async, .. } => { - let mut lines = vec![Cow::Borrowed("all functions in the public API must have an explicit return type")]; - if *is_definitely_void_or_never { - if *is_async { - lines.push(Cow::Borrowed("async function expressions without a return statement can have a return type of either 'Promise' or 'Promise'")); - } else { - lines.push(Cow::Borrowed("function expressions without a return statement can have a return type of either 'void' or 'never'")); - } - lines.push(Cow::Borrowed("this function has no return statements, so a return type could not be inferred automatically")); + UnknownVarType { cause, .. } => { + let mut lines = vec![Cow::Borrowed("all variables in the public API must have a known type")]; + if let Some(cause) = cause { + cause.info(&mut lines); + } else { + lines.push(Cow::Borrowed("variables without an initializer can not infer a type")); + } + Cow::Owned(lines) + }, + UnknownReturnType { cause, .. } => { + let mut lines = vec![Cow::Borrowed("all functions in the public API must have an known return type")]; + if let Some(cause) = cause { + cause.info(&mut lines, "a function declaration"); + } else { + lines.push(Cow::Borrowed("functions without a body can not infer a return type from the return value")); } Cow::Owned(lines) }, @@ -625,7 +709,8 @@ fn transform_package( .module_from_specifier(&specifier) .unwrap_or_else(|| panic!("module not found: {}", specifier)); if let Some(module_info) = module_info.esm() { - transform::transform(graph, module_info, &ranges, options).map(Some) + transform::transform(graph, module_info, root_symbol, &ranges, options) + .map(Some) } else { Ok(None) // nothing to transform } diff --git a/src/fast_check/swc_helpers.rs b/src/fast_check/swc_helpers.rs index e2fe1fead..79259b86b 100644 --- a/src/fast_check/swc_helpers.rs +++ b/src/fast_check/swc_helpers.rs @@ -1,8 +1,7 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use std::ops::ControlFlow; - use deno_ast::swc::ast::*; +use deno_ast::swc::common::SyntaxContext; use deno_ast::swc::common::DUMMY_SP; pub fn ident(name: String) -> Ident { @@ -20,101 +19,6 @@ pub fn ts_keyword_type(kind: TsKeywordTypeKind) -> TsType { }) } -#[derive(Debug)] -pub enum ReturnStatementAnalysis { - /// There are no return statements in the function body. - None, - /// There are only return statements without arguments in the function body, - /// or if the function body is empty. - Void, - /// There is only a single return statement in the function body, and it has - /// an argument. - Single(ReturnStmt), - /// There are multiple return statements in the function body, and at least - /// one of them has an argument. - Multiple, -} - -pub fn analyze_return_stmts_in_function_body( - body: &deno_ast::swc::ast::BlockStmt, -) -> ReturnStatementAnalysis { - if body.stmts.is_empty() { - ReturnStatementAnalysis::Void - } else { - let mut analysis = ReturnStatementAnalysis::None; - analyze_return_stmts_from_stmts(&body.stmts, &mut analysis); - analysis - } -} - -fn analyze_return_stmts_from_stmts( - stmts: &[Stmt], - analysis: &mut ReturnStatementAnalysis, -) -> ControlFlow<(), ()> { - for stmt in stmts { - analyze_return_stmts_from_stmt(stmt, analysis)?; - } - ControlFlow::Continue(()) -} - -fn analyze_return_stmts_from_stmt( - stmt: &Stmt, - analysis: &mut ReturnStatementAnalysis, -) -> ControlFlow<(), ()> { - match stmt { - Stmt::Block(n) => analyze_return_stmts_from_stmts(&n.stmts, analysis), - Stmt::With(n) => analyze_return_stmts_from_stmt(&n.body, analysis), - Stmt::Return(n) => { - match (&n.arg, &*analysis) { - (None, ReturnStatementAnalysis::None) => { - *analysis = ReturnStatementAnalysis::Void; - } - (None, ReturnStatementAnalysis::Void) => {} - (Some(_), ReturnStatementAnalysis::None) - | (Some(_), ReturnStatementAnalysis::Void) => { - *analysis = ReturnStatementAnalysis::Single(n.clone()); - } - (_, ReturnStatementAnalysis::Single(_)) => { - *analysis = ReturnStatementAnalysis::Multiple; - return ControlFlow::Break(()); - } - (_, ReturnStatementAnalysis::Multiple) => unreachable!(), // we break early when analysis is Multiple - } - ControlFlow::Continue(()) - } - Stmt::Labeled(n) => analyze_return_stmts_from_stmt(&n.body, analysis), - Stmt::If(n) => analyze_return_stmts_from_stmt(&n.cons, analysis), - Stmt::Switch(n) => { - for case in &n.cases { - analyze_return_stmts_from_stmts(&case.cons, analysis)?; - } - ControlFlow::Continue(()) - } - Stmt::Try(n) => { - analyze_return_stmts_from_stmts(&n.block.stmts, analysis)?; - if let Some(n) = &n.handler { - analyze_return_stmts_from_stmts(&n.body.stmts, analysis)?; - } - if let Some(n) = &n.finalizer { - analyze_return_stmts_from_stmts(&n.stmts, analysis)?; - } - ControlFlow::Continue(()) - } - Stmt::While(n) => analyze_return_stmts_from_stmt(&n.body, analysis), - Stmt::DoWhile(n) => analyze_return_stmts_from_stmt(&n.body, analysis), - Stmt::For(n) => analyze_return_stmts_from_stmt(&n.body, analysis), - Stmt::ForIn(n) => analyze_return_stmts_from_stmt(&n.body, analysis), - Stmt::ForOf(n) => analyze_return_stmts_from_stmt(&n.body, analysis), - Stmt::Break(_) - | Stmt::Continue(_) - | Stmt::Throw(_) - | Stmt::Debugger(_) - | Stmt::Decl(_) - | Stmt::Expr(_) - | Stmt::Empty(_) => ControlFlow::Continue(()), - } -} - pub fn is_void_type(return_type: &TsType) -> bool { is_keyword_type(return_type, TsKeywordTypeKind::TsVoidKeyword) } @@ -172,28 +76,122 @@ pub fn ts_tuple_element(ts_type: TsType) -> TsTupleElement { } } -pub fn maybe_lit_to_ts_type_const(lit: &Lit) -> Option { +pub fn lit_to_ts_type_const(lit: &Lit) -> TsType { match lit { - Lit::Str(lit_str) => Some(ts_lit_type(TsLit::Str(lit_str.clone()))), - Lit::Bool(lit_bool) => Some(ts_lit_type(TsLit::Bool(*lit_bool))), - Lit::Null(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNullKeyword)), - Lit::Num(lit_num) => Some(ts_lit_type(TsLit::Number(lit_num.clone()))), - Lit::BigInt(lit_bigint) => { - Some(ts_lit_type(TsLit::BigInt(lit_bigint.clone()))) + Lit::Str(lit_str) => ts_lit_type(TsLit::Str(lit_str.clone())), + Lit::Bool(lit_bool) => ts_lit_type(TsLit::Bool(*lit_bool)), + Lit::Null(_) => ts_keyword_type(TsKeywordTypeKind::TsNullKeyword), + Lit::Num(lit_num) => ts_lit_type(TsLit::Number(lit_num.clone())), + Lit::BigInt(lit_bigint) => ts_lit_type(TsLit::BigInt(lit_bigint.clone())), + Lit::Regex(_) => regex_type(), + Lit::JSXText(_) => { + unreachable!("jsx text can only happen inside of jsx elements") } - Lit::Regex(_) => Some(regex_type()), - Lit::JSXText(_) => None, } } -pub fn maybe_lit_to_ts_type(lit: &Lit) -> Option { +pub fn lit_to_ts_type(lit: &Lit) -> TsType { match lit { - Lit::Str(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsStringKeyword)), - Lit::Bool(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsBooleanKeyword)), - Lit::Null(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNullKeyword)), - Lit::Num(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNumberKeyword)), - Lit::BigInt(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsBigIntKeyword)), - Lit::Regex(_) => Some(regex_type()), - Lit::JSXText(_) => None, + Lit::Str(_) => ts_keyword_type(TsKeywordTypeKind::TsStringKeyword), + Lit::Bool(_) => ts_keyword_type(TsKeywordTypeKind::TsBooleanKeyword), + Lit::Null(_) => ts_keyword_type(TsKeywordTypeKind::TsNullKeyword), + Lit::Num(_) => ts_keyword_type(TsKeywordTypeKind::TsNumberKeyword), + Lit::BigInt(_) => ts_keyword_type(TsKeywordTypeKind::TsBigIntKeyword), + Lit::Regex(_) => regex_type(), + Lit::JSXText(_) => { + unreachable!("jsx text can only happen inside of jsx elements") + } + } +} + +pub fn prop_name_to_ts_key( + prop_name: &PropName, +) -> (Box, /* computed */ bool) { + match prop_name { + PropName::Ident(ident) => (Box::new(Expr::Ident(ident.clone())), false), + PropName::Str(str) => match Ident::verify_symbol(str.value.as_str()) { + Ok(_) => ( + Box::new(Expr::Ident(Ident::new(str.value.clone(), str.span))), + false, + ), + Err(_) => (Box::new(Expr::Lit(Lit::Str(str.clone()))), false), + }, + PropName::Num(num) => (Box::new(Expr::Lit(Lit::Num(num.clone()))), false), + PropName::Computed(expr) => { + // We leave the expression as is. See also https://github.com/microsoft/TypeScript/issues/58533 + (expr.expr.clone(), true) + } + PropName::BigInt(bigint) => { + (Box::new(Expr::Lit(Lit::BigInt(bigint.clone()))), false) + } + } +} + +pub fn void_or_promise_void(is_async: bool) -> Box { + let void_type = Box::new(ts_keyword_type(TsKeywordTypeKind::TsVoidKeyword)); + if is_async { + Box::new(TsType::TsTypeRef(TsTypeRef { + span: DUMMY_SP, + type_name: TsEntityName::Ident(Ident::new("Promise".into(), DUMMY_SP)), + type_params: Some(Box::new(TsTypeParamInstantiation { + span: DUMMY_SP, + params: vec![void_type], + })), + })) + } else { + void_type + } +} + +pub fn is_param_pat_optional(pat: &Pat) -> bool { + match pat { + Pat::Ident(ident) => ident.optional, + Pat::Array(a) => a.optional, + Pat::Object(o) => o.optional, + Pat::Assign(_) | Pat::Rest(_) => true, + Pat::Invalid(_) | Pat::Expr(_) => false, + } +} + +/// Looks if the call expr is `Symbol("example")` or `Symbol.for("example")` +pub fn is_call_expr_symbol_create( + call_expr: &CallExpr, + unresolved_context: SyntaxContext, +) -> bool { + let Some(expr) = call_expr.callee.as_expr() else { + return false; + }; + let (expr_ident, is_for) = match &**expr { + Expr::Ident(ident) => (ident, false), + Expr::Member(member_expr) => { + let Some(ident) = member_expr.obj.as_ident() else { + return false; + }; + let Some(prop_ident) = member_expr.prop.as_ident() else { + return false; + }; + if prop_ident.sym != "for" { + return false; + } + (ident, true) + } + _ => return false, + }; + + let is_symbol_global = + expr_ident.sym == "Symbol" && expr_ident.to_id().1 == unresolved_context; + if !is_symbol_global { + return false; + } + if !is_for && call_expr.args.is_empty() { + return true; + } + if call_expr.args.len() != 1 { + return false; } + let Some(arg_lit) = call_expr.args.first().and_then(|a| a.expr.as_lit()) + else { + return false; + }; + matches!(arg_lit, Lit::Str(_)) } diff --git a/src/fast_check/transform.rs b/src/fast_check/transform.rs index 12446970d..b2583b20a 100644 --- a/src/fast_check/transform.rs +++ b/src/fast_check/transform.rs @@ -25,8 +25,10 @@ use deno_ast::SourceRange; use deno_ast::SourceRangedForSpanned; use indexmap::IndexMap; +use crate::swc_helpers::FunctionKind; use crate::symbols::EsModuleInfo; use crate::symbols::ExpandoPropertyRef; +use crate::symbols::RootSymbol; use crate::symbols::Symbol; use crate::ModuleGraph; use crate::ModuleInfo; @@ -34,15 +36,15 @@ use crate::ParserModuleAnalyzer; use crate::WorkspaceMember; use super::range_finder::ModulePublicRanges; -use super::swc_helpers::analyze_return_stmts_in_function_body; use super::swc_helpers::any_type_ann; use super::swc_helpers::ident; use super::swc_helpers::is_void_type; -use super::swc_helpers::maybe_lit_to_ts_type; +use super::swc_helpers::lit_to_ts_type; use super::swc_helpers::ts_keyword_type; -use super::swc_helpers::ReturnStatementAnalysis; use super::transform_dts::FastCheckDtsDiagnostic; use super::transform_dts::FastCheckDtsTransformer; +use super::type_infer::ReturnTypeInferFailCause; +use super::type_infer::TypeInferrer; use super::FastCheckDiagnostic; use super::FastCheckDiagnosticRange; @@ -110,12 +112,14 @@ pub struct TransformOptions<'a> { pub fn transform( graph: &ModuleGraph, es_module_info: &EsModuleInfo, + root_symbol: &RootSymbol, public_ranges: &ModulePublicRanges, options: &TransformOptions, ) -> Result> { let mut transformer = FastCheckTransformer::new( graph, es_module_info, + root_symbol, public_ranges, options.should_error_on_first_diagnostic, ); @@ -209,6 +213,7 @@ struct FastCheckTransformer<'a> { graph: &'a ModuleGraph, specifier: &'a ModuleSpecifier, es_module_info: &'a EsModuleInfo, + root_symbol: &'a RootSymbol<'a>, public_ranges: &'a ModulePublicRanges, parsed_source: &'a ParsedSource, should_error_on_first_diagnostic: bool, @@ -220,6 +225,7 @@ impl<'a> FastCheckTransformer<'a> { pub fn new( graph: &'a ModuleGraph, es_module_info: &'a EsModuleInfo, + root_symbol: &'a RootSymbol<'a>, public_ranges: &'a ModulePublicRanges, should_error_on_first_diagnostic: bool, ) -> Self { @@ -227,6 +233,7 @@ impl<'a> FastCheckTransformer<'a> { graph, specifier: es_module_info.specifier(), es_module_info, + root_symbol, public_ranges, parsed_source: es_module_info.source(), should_error_on_first_diagnostic, @@ -828,7 +835,7 @@ impl<'a> FastCheckTransformer<'a> { _ => None, }; explicit_type_ann.or_else(|| { - self.maybe_infer_type_from_expr(&assign.right).map( + self.maybe_infer_type_from_expr_old(&assign.right).map( |type_ann| { Box::new(TsTypeAnn { span: DUMMY_SP, @@ -980,7 +987,7 @@ impl<'a> FastCheckTransformer<'a> { let inferred_type = n .value .as_ref() - .and_then(|e| self.maybe_infer_type_from_expr(e)); + .and_then(|e| self.maybe_infer_type_from_expr_old(e)); match inferred_type { Some(t) => { n.type_ann = Some(Box::new(TsTypeAnn { @@ -1029,7 +1036,7 @@ impl<'a> FastCheckTransformer<'a> { let inferred_type = n .value .as_ref() - .and_then(|e| self.maybe_infer_type_from_expr(e)); + .and_then(|e| self.maybe_infer_type_from_expr_old(e)); match inferred_type { Some(t) => Box::new(TsTypeAnn { span: DUMMY_SP, @@ -1139,21 +1146,30 @@ impl<'a> FastCheckTransformer<'a> { if missing_return_type { let range = parent_id_range.unwrap_or_else(|| n.range()); if n.is_generator { - self.mark_diagnostic( - FastCheckDiagnostic::MissingExplicitReturnType { - range: self.source_range_to_range(range), - is_definitely_void_or_never: false, - is_async: n.is_async, - }, - )?; + self.mark_diagnostic(FastCheckDiagnostic::UnknownReturnType { + ident: self.source_range_to_range(range), + cause: Some(Box::new(ReturnTypeInferFailCause::IsGenerator)), + })?; } else if let Some(body) = &mut n.body { - self.transform_function_body_block_stmt( - range, - &mut n.return_type, + let res = self.infer().infer_function_body_block_stmt( body, function_kind, n.is_async, - )?; + ); + match res { + Ok(type_ann) => { + n.return_type = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann, + })); + } + Err(cause) => { + self.mark_diagnostic(FastCheckDiagnostic::UnknownReturnType { + ident: self.source_range_to_range(range), + cause: Some(Box::new(cause)), + })?; + } + } } } @@ -1203,19 +1219,30 @@ impl<'a> FastCheckTransformer<'a> { match &mut *n.body { BlockStmtOrExpr::BlockStmt(body) => { - self.transform_function_body_block_stmt( - range, - &mut n.return_type, + let res = self.infer().infer_function_body_block_stmt( body, FunctionKind::ExpressionLike, n.is_async, - )?; + ); + match res { + Ok(type_ann) => { + n.return_type = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann, + })); + } + Err(cause) => { + self.mark_diagnostic(FastCheckDiagnostic::UnknownReturnType { + ident: self.source_range_to_range(range), + cause: Some(Box::new(cause)), + })?; + } + } } BlockStmtOrExpr::Expr(expr) => { - let inferred_type = self.maybe_infer_type_from_expr(expr); - match inferred_type { - Some(t) => { - let mut return_type = Box::new(t); + let res = self.infer().infer_expr(expr, false, None); + match res { + Ok(mut return_type) => { if n.is_async { return_type = self.promise_wrap_type(return_type) } @@ -1224,18 +1251,15 @@ impl<'a> FastCheckTransformer<'a> { type_ann: return_type, })); } - None => { - let is_expr_leavable = - self.maybe_transform_expr_if_leavable(expr, None)?; - if !is_expr_leavable { - self.mark_diagnostic( - FastCheckDiagnostic::MissingExplicitReturnType { - range: self.source_range_to_range(range), - is_definitely_void_or_never: false, - is_async: n.is_async, + Err(cause) => { + self.mark_diagnostic(FastCheckDiagnostic::UnknownReturnType { + ident: self.source_range_to_range(range), + cause: Some(Box::new( + ReturnTypeInferFailCause::ArrowExpressionValue { + cause: Box::new(cause), }, - )?; - } + )), + })?; } } } @@ -1267,60 +1291,6 @@ impl<'a> FastCheckTransformer<'a> { Ok(()) } - fn transform_function_body_block_stmt( - &mut self, - range: SourceRange, - return_type: &mut Option>, - body: &mut BlockStmt, - function_kind: FunctionKind, - is_async: bool, - ) -> Result<(), Vec> { - let analysis = analyze_return_stmts_in_function_body(body); - match (analysis, function_kind) { - (_, FunctionKind::Setter) => unreachable!(), - (ReturnStatementAnalysis::None, FunctionKind::DeclarationLike) - | (ReturnStatementAnalysis::Void, FunctionKind::DeclarationLike) - | (ReturnStatementAnalysis::Void, FunctionKind::ExpressionLike) => { - *return_type = Some(Box::new(TsTypeAnn { - span: DUMMY_SP, - type_ann: void_or_promise_void(is_async), - })); - } - (ReturnStatementAnalysis::None, FunctionKind::ExpressionLike) => { - self.mark_diagnostic( - FastCheckDiagnostic::MissingExplicitReturnType { - range: self.source_range_to_range(range), - is_definitely_void_or_never: true, - is_async, - }, - )?; - } - (ReturnStatementAnalysis::Single(_), _) => { - // TODO: infer return type based on return type - self.mark_diagnostic( - FastCheckDiagnostic::MissingExplicitReturnType { - range: self.source_range_to_range(range), - is_definitely_void_or_never: false, - is_async, - }, - )?; - } - (ReturnStatementAnalysis::None, FunctionKind::Getter) - | (ReturnStatementAnalysis::Void, FunctionKind::Getter) - | (ReturnStatementAnalysis::Multiple, _) => { - self.mark_diagnostic( - FastCheckDiagnostic::MissingExplicitReturnType { - range: self.source_range_to_range(range), - is_definitely_void_or_never: false, - is_async, - }, - )?; - } - } - - Ok(()) - } - fn handle_param_pat( &mut self, pat: &mut Pat, @@ -1337,7 +1307,8 @@ impl<'a> FastCheckTransformer<'a> { Pat::Assign(assign) => match &mut *assign.left { Pat::Ident(ident) => { if ident.type_ann.is_none() { - let inferred_type = self.maybe_infer_type_from_expr(&assign.right); + let inferred_type = + self.maybe_infer_type_from_expr_old(&assign.right); match inferred_type { Some(t) => { ident.type_ann = Some(Box::new(TsTypeAnn { @@ -1458,8 +1429,9 @@ impl<'a> FastCheckTransformer<'a> { // don't need to do anything for ambient decls if !is_ambient { for decl in &mut n.decls { - self.transform_var_declarator(decl)?; + self.transform_var_declarator(decl, n.kind)?; } + n.declare = true; } Ok(TransformItemResult::from_retain(!n.decls.is_empty())) @@ -1468,41 +1440,43 @@ impl<'a> FastCheckTransformer<'a> { fn transform_var_declarator( &mut self, n: &mut VarDeclarator, + kind: VarDeclKind, ) -> Result<(), Vec> { match &mut n.name { Pat::Ident(ident) => { if ident.type_ann.is_none() { - let inferred_type = n - .init - .as_ref() - .and_then(|e| self.maybe_infer_type_from_expr(e)); - match inferred_type { - Some(t) => { - ident.type_ann = Some(Box::new(TsTypeAnn { - span: DUMMY_SP, - type_ann: Box::new(t), - })); - n.init = Some(obj_as_never_expr()); - } - None => { - let is_init_leavable = match n.init.as_mut() { - Some(init) => self.maybe_transform_expr_if_leavable( - init, - Some(ident.id.range()), - )?, - None => false, - }; - if !is_init_leavable { - self.mark_diagnostic( - FastCheckDiagnostic::MissingExplicitType { - range: self.source_range_to_range(ident.range()), - }, - )?; + if kind == VarDeclKind::Const { + self.transform_const_decl( + ident.range(), + &mut n.init, + &mut ident.type_ann, + ident.id.range(), + )?; + } else { + if let Some(expr) = n.init.as_mut() { + let res = + self.infer().infer_expr(expr, false, Some(ident.id.range())); + n.init = None; + match res { + Ok(type_ann) => { + ident.type_ann = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann, + })); + } + Err(cause) => { + self.mark_diagnostic( + FastCheckDiagnostic::UnknownVarType { + ident: self.source_range_to_range(ident.range()), + cause: Some(Box::new(cause)), + }, + )?; + } } } } } else { - n.init = Some(obj_as_never_expr()); + n.init = None; } } Pat::Array(_) @@ -1522,6 +1496,62 @@ impl<'a> FastCheckTransformer<'a> { Ok(()) } + fn transform_const_decl( + &mut self, + range: SourceRange, + init_opt: &mut Option>, + type_ann: &mut Option>, + ident_range: SourceRange, + ) -> Result<(), Vec> { + let init = init_opt.as_mut().unwrap(); + + let res = self + .infer() + .infer_expr_in_const_pos(init, Some(ident_range)); + let inferred_type = match res { + Ok(inferred_type) => inferred_type, + Err(cause) => { + self.mark_diagnostic(FastCheckDiagnostic::UnknownVarType { + ident: self.source_range_to_range(range), + cause: Some(Box::new(cause)), + })?; + return Ok(()); + } + }; + + if let TsType::TsLitType(lit) = &*inferred_type { + match &lit.lit { + TsLit::Number(number) => { + **init = Expr::Lit(Lit::Num(number.clone())); + } + TsLit::Str(str) => { + **init = Expr::Lit(Lit::Str(str.clone())); + } + TsLit::Bool(bool) => { + **init = Expr::Lit(Lit::Bool(bool.clone())); + } + TsLit::BigInt(bigint) => { + **init = Expr::Lit(Lit::BigInt(bigint.clone())); + } + TsLit::Tpl(_) => { + *init_opt = None; + *type_ann = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann: inferred_type, + })); + } + } + } else { + *init_opt = None; + *type_ann = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann: inferred_type, + })); + } + + Ok(()) + } + fn transform_ts_module( &mut self, n: &mut TsModuleDecl, @@ -1663,6 +1693,15 @@ impl<'a> FastCheckTransformer<'a> { } } + fn infer(&self) -> TypeInferrer<'_> { + TypeInferrer::new( + self.specifier, + self.parsed_source, + self.es_module_info, + self.root_symbol, + ) + } + fn maybe_transform_expr_if_leavable( &mut self, expr: &mut Expr, @@ -1783,11 +1822,11 @@ impl<'a> FastCheckTransformer<'a> { Ok(is_leavable) } - fn maybe_infer_type_from_expr(&self, expr: &Expr) -> Option { + fn maybe_infer_type_from_expr_old(&self, expr: &Expr) -> Option { match expr { Expr::TsTypeAssertion(n) => infer_simple_type_from_type(&n.type_ann), Expr::TsAs(n) => infer_simple_type_from_type(&n.type_ann), - Expr::Lit(lit) => maybe_lit_to_ts_type(lit), + Expr::Lit(lit) => Some(lit_to_ts_type(lit)), Expr::Call(call_expr) => { if self.is_call_expr_symbol_create(call_expr) { Some(TsType::TsTypeOperator(TsTypeOperator { @@ -1803,7 +1842,7 @@ impl<'a> FastCheckTransformer<'a> { None } } - Expr::Paren(n) => self.maybe_infer_type_from_expr(&n.expr), + Expr::Paren(n) => self.maybe_infer_type_from_expr_old(&n.expr), Expr::This(_) | Expr::Array(_) | Expr::Object(_) @@ -1898,17 +1937,6 @@ impl<'a> FastCheckTransformer<'a> { } } -enum FunctionKind { - /// function declarations, class method declarations (both class decl and class expr) - DeclarationLike, - /// function expressions, arrow functions, object method shorthand properties - ExpressionLike, - /// getters, both on classes and object literals - Getter, - /// setters, both on classes and object literals - Setter, -} - fn is_ts_private_computed_class_member(m: &ClassMember) -> bool { match m { ClassMember::Method(m) => { @@ -1949,22 +1977,6 @@ fn is_computed_prop_name(prop_name: &PropName) -> bool { } } -fn void_or_promise_void(is_async: bool) -> Box { - let void_type = Box::new(ts_keyword_type(TsKeywordTypeKind::TsVoidKeyword)); - if is_async { - Box::new(TsType::TsTypeRef(TsTypeRef { - span: DUMMY_SP, - type_name: TsEntityName::Ident(Ident::new("Promise".into(), DUMMY_SP)), - type_params: Some(Box::new(TsTypeParamInstantiation { - span: DUMMY_SP, - params: vec![void_type], - })), - })) - } else { - void_type - } -} - fn replacement_return_value(ty: &TsType) -> Option> { if is_void_type(ty) { None diff --git a/src/fast_check/transform_dts.rs b/src/fast_check/transform_dts.rs index 0852b383b..2b4c5e3b1 100644 --- a/src/fast_check/transform_dts.rs +++ b/src/fast_check/transform_dts.rs @@ -9,8 +9,8 @@ use crate::FastCheckDiagnostic; use crate::FastCheckDiagnosticRange; use super::swc_helpers::any_type_ann; -use super::swc_helpers::maybe_lit_to_ts_type; -use super::swc_helpers::maybe_lit_to_ts_type_const; +use super::swc_helpers::lit_to_ts_type; +use super::swc_helpers::lit_to_ts_type_const; use super::swc_helpers::ts_readonly; use super::swc_helpers::ts_tuple_element; use super::swc_helpers::type_ann; @@ -409,9 +409,9 @@ impl<'a> FastCheckDtsTransformer<'a> { } Expr::Lit(lit) => { if as_const { - maybe_lit_to_ts_type_const(&lit) + Some(lit_to_ts_type_const(&lit)) } else { - maybe_lit_to_ts_type(&lit) + Some(lit_to_ts_type(&lit)) } } Expr::TsConstAssertion(ts_const) => { diff --git a/src/fast_check/type_infer.rs b/src/fast_check/type_infer.rs new file mode 100644 index 000000000..1a3922085 --- /dev/null +++ b/src/fast_check/type_infer.rs @@ -0,0 +1,1267 @@ +use std::borrow::Cow; + +use deno_ast::diagnostics::DiagnosticSnippetHighlight; +use deno_ast::diagnostics::DiagnosticSnippetHighlightStyle; +use deno_ast::swc::ast::ArrayLit; +use deno_ast::swc::ast::ArrowExpr; +use deno_ast::swc::ast::BindingIdent; +use deno_ast::swc::ast::BlockStmt; +use deno_ast::swc::ast::BlockStmtOrExpr; +use deno_ast::swc::ast::Expr; +use deno_ast::swc::ast::Function; +use deno_ast::swc::ast::Ident; +use deno_ast::swc::ast::ObjectLit; +use deno_ast::swc::ast::ObjectPatProp; +use deno_ast::swc::ast::Pat; +use deno_ast::swc::ast::Prop; +use deno_ast::swc::ast::PropOrSpread; +use deno_ast::swc::ast::Str; +use deno_ast::swc::ast::Tpl; +use deno_ast::swc::ast::TsEntityName; +use deno_ast::swc::ast::TsFnOrConstructorType; +use deno_ast::swc::ast::TsFnParam; +use deno_ast::swc::ast::TsFnType; +use deno_ast::swc::ast::TsGetterSignature; +use deno_ast::swc::ast::TsKeywordTypeKind; +use deno_ast::swc::ast::TsLit; +use deno_ast::swc::ast::TsMethodSignature; +use deno_ast::swc::ast::TsPropertySignature; +use deno_ast::swc::ast::TsSetterSignature; +use deno_ast::swc::ast::TsTupleElement; +use deno_ast::swc::ast::TsTupleType; +use deno_ast::swc::ast::TsType; +use deno_ast::swc::ast::TsTypeAnn; +use deno_ast::swc::ast::TsTypeElement; +use deno_ast::swc::ast::TsTypeLit; +use deno_ast::swc::ast::TsTypeOperator; +use deno_ast::swc::ast::TsTypeOperatorOp; +use deno_ast::swc::common::Spanned; +use deno_ast::swc::common::DUMMY_SP; +use deno_ast::swc::visit::Visit; +use deno_ast::swc::visit::VisitWith; +use deno_ast::ModuleSpecifier; +use deno_ast::ParsedSource; +use deno_ast::SourceRange; +use deno_ast::SourceRangedForSpanned; + +use crate::swc_helpers::analyze_return_stmts_in_function_body; +use crate::swc_helpers::FunctionKind; +use crate::swc_helpers::ts_entity_name_to_parts; +use crate::swc_helpers::ReturnStatementAnalysis; +use crate::symbols::DefinitionPathNode; +use crate::symbols::EsModuleInfo; +use crate::symbols::ModuleInfoRef; +use crate::symbols::ResolvedSymbolDepEntry; +use crate::symbols::RootSymbol; +use crate::symbols::SymbolNodeDep; +use crate::FastCheckDiagnosticRange; + +use super::swc_helpers::is_call_expr_symbol_create; +use super::swc_helpers::is_param_pat_optional; +use super::swc_helpers::lit_to_ts_type; +use super::swc_helpers::lit_to_ts_type_const; +use super::swc_helpers::prop_name_to_ts_key; +use super::swc_helpers::ts_keyword_type; +use super::swc_helpers::ts_lit_type; +use super::swc_helpers::void_or_promise_void; + +#[derive(Debug, Clone)] +pub enum ExprInferFailCause { + ObjectLitSpread { + dot3_token: FastCheckDiagnosticRange, + }, + ObjectLitShorthand { + key: FastCheckDiagnosticRange, + }, + ArrayWithoutAsConst { + expr: FastCheckDiagnosticRange, + }, + ArraySpread { + dot3_token: FastCheckDiagnosticRange, + }, + ExprInTemplateLiteral { + expr: FastCheckDiagnosticRange, + }, + + ObjectGetter { + key: FastCheckDiagnosticRange, + cause: Box, + }, + ObjectSetter { + key: FastCheckDiagnosticRange, + cause: Box, + }, + ObjectMethod { + key: FastCheckDiagnosticRange, + cause: Box, + }, + + FunctionExpression { + name: FastCheckDiagnosticRange, + cause: Box, + }, + ArrowExpression { + name: FastCheckDiagnosticRange, + cause: Box, + }, + + LocalReference { + ident: FastCheckDiagnosticRange, + }, + + Other { + expr: FastCheckDiagnosticRange, + }, +} + +impl ExprInferFailCause { + pub fn highlights(&self, highlights: &mut Vec) { + // this is always prefixed with + // "this function's return type could not be inferred because the value returned here" + // "this function's return type could not be inferred because the returned value" + // "this variable's type could not be inferred because its initializer" + match self { + ExprInferFailCause::ObjectLitSpread { dot3_token } => { + highlights.push(DiagnosticSnippetHighlight { + range: dot3_token.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed( + "contains this spread property, which can not be inferred", + )), + }) + } + ExprInferFailCause::ObjectLitShorthand { key } => { + highlights.push(DiagnosticSnippetHighlight { + range: key.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed( + "contains this shorthand property, which can not be inferred", + )), + }) + } + ExprInferFailCause::ArrayWithoutAsConst { expr } => { + highlights.push(DiagnosticSnippetHighlight { + range: expr.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed( + "contains this array literal, which can not be inferred unless marked 'as const'", + )), + }) + } + ExprInferFailCause::ArraySpread { dot3_token } => { + highlights.push(DiagnosticSnippetHighlight { + range: dot3_token.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed( + "contains this spread element, which can not be inferred", + )), + }) + } + ExprInferFailCause::ExprInTemplateLiteral { expr } => { + highlights.push(DiagnosticSnippetHighlight { + range: expr.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed( + "contains this expression in a template literal, which can not be inferred", + )), + }) + }, + ExprInferFailCause::ObjectGetter { key, cause } => { + cause.highlights(highlights, key, "contains this object getter", true); + }, + ExprInferFailCause::ObjectSetter { key, cause } => { + cause.highlights(highlights, key, "contains this object setter", true); + }, + ExprInferFailCause::ObjectMethod { key, cause } => { + cause.highlights(highlights, key, "contains this object method", true); + }, + ExprInferFailCause::FunctionExpression { name, cause } => { + cause.highlights(highlights, name, "contains this function expression", true); + }, + ExprInferFailCause::ArrowExpression { name, cause } => { + cause.highlights(highlights, name, "contains this arrow expression", true); + }, + ExprInferFailCause::LocalReference { ident } => { + highlights.push(DiagnosticSnippetHighlight { + range: ident.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed( + "contains this reference to a local variable or type", + )), + }) + }, + ExprInferFailCause::Other { expr } => { + highlights.push(DiagnosticSnippetHighlight { + range: expr.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed( + "contains this expression, of which the type could not be inferred", + )), + }) + } + } + } + + pub fn hint(&self, location: Cow<'_, str>) -> Option { + match self { + ExprInferFailCause::ObjectLitSpread { .. } => None, + ExprInferFailCause::ObjectLitShorthand { .. } => None, + ExprInferFailCause::ArrayWithoutAsConst { .. } => None, + ExprInferFailCause::ArraySpread { .. } => None, + ExprInferFailCause::ExprInTemplateLiteral { .. } => None, + ExprInferFailCause::ObjectGetter { cause, .. } => { + cause.hint("object getter", location) + } + ExprInferFailCause::ObjectSetter { cause, .. } => { + cause.hint("object setter", location) + } + ExprInferFailCause::ObjectMethod { cause, .. } => { + cause.hint("object method", location) + } + ExprInferFailCause::FunctionExpression { cause, .. } => { + cause.hint("function expression", location) + } + ExprInferFailCause::ArrowExpression { cause, .. } => { + cause.hint("arrow expression", location) + } + ExprInferFailCause::LocalReference { .. } => None, + ExprInferFailCause::Other { .. } => None, + } + } + + pub fn info(&self, infos: &mut Vec>) { + match self { + ExprInferFailCause::ObjectLitSpread { .. } => { + infos.push(Cow::Borrowed("spread properties can not be inferred because the type of the resulting object can not be narrowed without a type checker")) + } + ExprInferFailCause::ObjectLitShorthand { .. } => { + infos.push(Cow::Borrowed("shorthand properties can not be inferred because the type of the value referred to by the shorthand property is not known without a type checker")) + } + ExprInferFailCause::ArrayWithoutAsConst { .. } => { + infos.push(Cow::Borrowed("array literals without 'as const' can not be inferred because the type of the array can not be narrowed without a type checker")); + } + ExprInferFailCause::ArraySpread { .. } => { + infos.push(Cow::Borrowed("spread elements can not be inferred because the type of the resulting array can not be narrowed without a type checker")); + } + ExprInferFailCause::ExprInTemplateLiteral { .. } => { + infos.push(Cow::Borrowed("expressions in template literals can not be inferred because the type of the resulting string can not be narrowed without a type checker")); + }, + ExprInferFailCause::ObjectGetter { cause, .. } => { + cause.info(infos, "an object getter"); + } + ExprInferFailCause::ObjectSetter { cause, ..} => { + cause.info(infos, "an object setter"); + }, + ExprInferFailCause::ObjectMethod { cause, .. } => { + cause.info(infos, "an object method"); + }, + ExprInferFailCause::FunctionExpression { cause, .. } => { + cause.info(infos, "a function expression"); + }, + ExprInferFailCause::ArrowExpression { cause, .. } => { + cause.info(infos, "an arrow expression"); + }, + ExprInferFailCause::LocalReference { .. } => { + infos.push(Cow::Borrowed("local variables or types can not be referenced in the public API because they are not visible at the top level of the module")); + }, + ExprInferFailCause::Other { .. } => infos.push(Cow::Borrowed("the type of arbitrary expressions can not be inferred without a type checker")), + } + } +} + +#[derive(Debug, Clone)] +pub enum FunctionInferFailCause { + ParamType { + pat: FastCheckDiagnosticRange, + cause: Option>, + }, + RequiredParamAfterOptional { + pat: FastCheckDiagnosticRange, + }, + ReturnType { + cause: Box, + }, +} + +impl FunctionInferFailCause { + fn highlights( + &self, + highlights: &mut Vec, + ident: &FastCheckDiagnosticRange, + prefix: &'static str, + which: bool, + ) { + match self { + FunctionInferFailCause::ParamType { pat, cause } => { + highlights.push(DiagnosticSnippetHighlight { + range: ident.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed(prefix)), + }); + let description = match (which, cause.is_some()) { + (false, false) => "has this parameter, the type of which could not be inferred because the default value", + (false, true) => "has this parameter, which is missing an explicit type annotation", + (true, false) => "which has this parameter, the type of which could not be inferred from the default value", + (true, true) => "which has this parameter, which is missing an explicit type annotation", + }; + highlights.push(DiagnosticSnippetHighlight { + range: pat.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed(description)), + }); + if let Some(cause) = cause { + cause.highlights(highlights); + } + } + FunctionInferFailCause::RequiredParamAfterOptional { pat } => { + highlights.push(DiagnosticSnippetHighlight { + range: ident.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed(prefix)), + }); + let description = if which { + "which has this required parameter following an optional parameter or a parameter with a default value" + } else { + "has this required parameter following an optional parameter or a parameter with a default value" + }; + highlights.push(DiagnosticSnippetHighlight { + range: pat.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed(description)), + }); + } + FunctionInferFailCause::ReturnType { cause } => { + cause.highlights(highlights, ident, prefix, which); + } + } + } + + fn hint( + &self, + subject: &'static str, + location: Cow<'_, str>, + ) -> Option { + match self { + FunctionInferFailCause::ParamType { cause, .. } => { + let hint = cause.as_ref().and_then(|cause| cause.hint(format!(" in the {subject} parameter{location}").into())) + .unwrap_or_else(|| format!("add an explicit type annotation to the {subject} parameter{location}")); + Some(hint) + } + FunctionInferFailCause::RequiredParamAfterOptional { .. } => { + Some(format!( + "make the {subject} parameter{location} optional or provide a default value" + ).into()) + }, + FunctionInferFailCause::ReturnType { cause } => { + let hint = cause.hint(subject, &location) + .unwrap_or_else(|| format!("add an explicit return type annotation to the {subject}{location}").into()); + Some(hint) + }, + } + } + + fn info(&self, infos: &mut Vec>, subject: &str) { + match self { + FunctionInferFailCause::ParamType { cause, .. } => { + if let Some(cause) = cause { + cause.info(infos) + } else { + infos.push(Cow::Owned(format!("all parameters of {subject} must have an explicit type annotation or an inferrable default value"))); + } + } + FunctionInferFailCause::RequiredParamAfterOptional { .. } => { + infos.push(Cow::Owned(format!("all required parameters of {subject} must precede optional parameters or parameters with default values"))); + infos.push(Cow::Borrowed("this is because to compute the type of a optional parameter that is followed by a required parameter, a type checker is needed")); + } + FunctionInferFailCause::ReturnType { cause } => { + cause.info(infos, subject); + } + } + } +} + +#[derive(Debug, Clone)] +pub enum ReturnTypeInferFailCause { + IsGenerator, + NoReturnStmt { + is_async: bool, + }, + NoValueReturnStmt, // getter only + ReturnStmtValue { + return_keyword: FastCheckDiagnosticRange, + cause: Box, + }, + ArrowExpressionValue { + cause: Box, + }, + MultipleReturnStmts, +} + +impl ReturnTypeInferFailCause { + pub fn highlights( + &self, + highlights: &mut Vec, + ident: &FastCheckDiagnosticRange, + prefix: &'static str, + which: bool, + ) { + match self { + ReturnTypeInferFailCause::IsGenerator + | ReturnTypeInferFailCause::NoReturnStmt { .. } + | ReturnTypeInferFailCause::NoValueReturnStmt + | ReturnTypeInferFailCause::MultipleReturnStmts => { + highlights.push(DiagnosticSnippetHighlight { + range: ident.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Owned(format!( + "{prefix}{} is missing an explicit return type annotation", + if which { ", which" } else { "" } + ))), + }); + } + ReturnTypeInferFailCause::ReturnStmtValue { + return_keyword, + cause, + } => { + highlights.push(DiagnosticSnippetHighlight { + range: ident.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Owned(format!( + "{prefix}{} return type could not be inferred", + if which { ", of which the" } else { "'s" } + ))), + }); + highlights.push(DiagnosticSnippetHighlight { + range: return_keyword.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Borrowed("because the value returned here")), + }); + cause.highlights(highlights); + } + ReturnTypeInferFailCause::ArrowExpressionValue { cause } => { + highlights.push(DiagnosticSnippetHighlight { + range: ident.into_diagnostic_range(), + style: DiagnosticSnippetHighlightStyle::Hint, + description: Some(Cow::Owned(format!( + "{prefix}{} return type could not be inferred from the returned value", + if which { ", of which the" } else { "'s" } + ))), + }); + cause.highlights(highlights); + } + }; + } + + pub fn hint(&self, subject: &'static str, location: &str) -> Option { + match self { + ReturnTypeInferFailCause::IsGenerator + | ReturnTypeInferFailCause::NoReturnStmt { .. } + | ReturnTypeInferFailCause::NoValueReturnStmt + | ReturnTypeInferFailCause::MultipleReturnStmts => None, + ReturnTypeInferFailCause::ReturnStmtValue { cause, .. } + | ReturnTypeInferFailCause::ArrowExpressionValue { cause } => { + cause.hint(format!(" in the {subject} return value{location}").into()) + } + } + } + + pub fn info(&self, infos: &mut Vec>, subject: &str) { + match self { + ReturnTypeInferFailCause::IsGenerator => { + infos.push(Cow::Owned(format!("{subject} that is a generator must have an explicit return type annotation because the return type can not be inferred without a type checker"))); + } + ReturnTypeInferFailCause::NoReturnStmt { is_async } => { + infos.push(Cow::Owned(format!("the return type of {subject} can not be inferred if it has no return statements"))); + if *is_async { + infos.push(Cow::Owned(format!("this is because async {subject}s without a return statement can either return 'Promise' or 'Promise', and the specific type can not be determined without a type checker"))); + } else { + infos.push(Cow::Owned(format!("this is because {subject}s without a return statement can either return 'void' or 'never', and the specific type can not be determined without a type checker"))); + } + } + ReturnTypeInferFailCause::NoValueReturnStmt => { + infos.push(Cow::Owned(format!("{subject} does not have a return statement with a value, which is required to infer the return type"))); + infos.push(Cow::Borrowed( + "this is because getters must have a return statement with a value", + )); + } + ReturnTypeInferFailCause::ReturnStmtValue { cause, .. } => { + cause.info(infos); + } + ReturnTypeInferFailCause::ArrowExpressionValue { cause } => { + cause.info(infos); + } + ReturnTypeInferFailCause::MultipleReturnStmts => { + infos.push(Cow::Owned(format!("{subject} has multiple return statements with values, so a return type can not be inferred without a type checker"))); + } + } + } +} + +pub struct TypeInferrer<'a> { + specifier: &'a ModuleSpecifier, + parsed_source: &'a ParsedSource, + module_info: &'a EsModuleInfo, + root_symbol: &'a RootSymbol<'a>, +} + +impl<'a> TypeInferrer<'a> { + pub fn new( + specifier: &'a ModuleSpecifier, + parsed_source: &'a ParsedSource, + module_info: &'a EsModuleInfo, + root_symbol: &'a RootSymbol<'a>, + ) -> Self { + Self { + specifier, + parsed_source, + module_info, + root_symbol, + } + } + + fn source_range_to_range( + &self, + range: SourceRange, + ) -> FastCheckDiagnosticRange { + FastCheckDiagnosticRange { + specifier: self.specifier.clone(), + text_info: self.parsed_source.text_info().clone(), + range, + } + } + + /// Infer a type from an expression in a non `const x = ...` context. + pub fn infer_expr( + &self, + expr: &Expr, + as_const: bool, + ident_range: Option, + ) -> Result, ExprInferFailCause> { + let err_other = || { + Err(ExprInferFailCause::Other { + expr: self.source_range_to_range(expr.range()), + }) + }; + + match expr { + Expr::Paren(n) => self.infer_expr(&n.expr, as_const, ident_range), + Expr::TsSatisfies(n) => self.infer_expr(&n.expr, as_const, ident_range), + Expr::Seq(n) => { + self.infer_expr(n.exprs.last().unwrap(), as_const, ident_range) + } + Expr::Assign(n) => self.infer_expr(&n.right, as_const, ident_range), + + Expr::Lit(lit) => { + if as_const { + Ok(Box::new(lit_to_ts_type_const(lit))) + } else { + Ok(Box::new(lit_to_ts_type(lit))) + } + } + Expr::Tpl(tpl) => { + if as_const { + self.infer_tpl_const(tpl) + } else { + Ok(Box::new(ts_keyword_type( + TsKeywordTypeKind::TsStringKeyword, + ))) + } + } + + Expr::Object(n) => self.infer_object_lit(n, as_const), + Expr::Array(n) => self.infer_array_lit(n, as_const), + + Expr::Call(n) => { + if is_call_expr_symbol_create( + n, + self.parsed_source.unresolved_context(), + ) { + Ok(Box::new(ts_keyword_type( + TsKeywordTypeKind::TsSymbolKeyword, + ))) + } else { + // Can not infer because we don't know the return type of the function being called + err_other() + } + } + Expr::Ident(i) => { + let is_symbol_global = i.sym == "undefined" + && i.to_id().1 == self.parsed_source.unresolved_context(); + if is_symbol_global { + Ok(Box::new(ts_keyword_type( + TsKeywordTypeKind::TsUndefinedKeyword, + ))) + } else { + // Can not infer because we don't know the type of the identifier + err_other() + } + } + Expr::TsTypeAssertion(n) => { + self.ensure_valid_type_ann(&n.type_ann)?; + Ok(n.type_ann.clone()) + } + Expr::TsAs(n) => { + self.ensure_valid_type_ann(&n.type_ann)?; + Ok(n.type_ann.clone()) + } + Expr::TsConstAssertion(n) => self.infer_expr(&n.expr, true, ident_range), + + Expr::Fn(n) => { + let ident_range = n + .ident + .as_ref() + .map(|ident| ident.span.range()) + .or(ident_range) + .unwrap_or_else(|| { + let range = n.function.span.range(); + SourceRange::new(range.start, range.start + 1) // this could be improved + }); + self.infer_fn(&n.function).map_err(|cause| { + ExprInferFailCause::FunctionExpression { + name: self.source_range_to_range(ident_range), + cause: Box::new(cause), + } + }) + } + Expr::Arrow(n) => { + let ident_range = ident_range.unwrap_or_else(|| { + let range = n.span.range(); + SourceRange::new(range.start, range.start + 1) + }); + self.infer_arrow(&n).map_err(|cause| { + ExprInferFailCause::ArrowExpression { + name: self.source_range_to_range(ident_range), + cause: Box::new(cause), + } + }) + } + + Expr::Unary(_) => { + // TODO(@lucacasonato): maybe support `void`? + err_other() + } + Expr::Bin(_) => { + // TODO(@lucacasonato): maybe support inferring comparison operators and `in` and `instanceof`? + err_other() + } + Expr::Class(_) => { + // TODO(@lucacasonato): maybe support inferring class expressions + err_other() + } + Expr::MetaProp(_) | Expr::Update(_) => err_other(), // Does not make sense to infer, usage not frequent for possible inferences + Expr::This(_) => err_other(), // Can not infer because we don't know the type of this + Expr::TsInstantiation(_) => err_other(), // Can not infer because we don't know the type being instantiated + Expr::Member(_) | Expr::SuperProp(_) | Expr::OptChain(_) => err_other(), // Can not infer because we don't know the type of the object being accessed + Expr::New(_) | Expr::TaggedTpl(_) => err_other(), // Can not infer because we don't know the type of the function being called + Expr::Yield(_) => err_other(), // Can not infer because we don't know the type of the generators next value + Expr::Cond(_) => err_other(), // Can not narrow the type of branches without type information + Expr::JSXMember(_) + | Expr::JSXNamespacedName(_) + | Expr::JSXEmpty(_) + | Expr::JSXElement(_) + | Expr::JSXFragment(_) => err_other(), // Can not infer because we don't know the type of the JSX element + Expr::Await(_) | Expr::TsNonNull(_) => err_other(), // Can not infer because we need type information to narrow the inner type + Expr::PrivateName(_) => err_other(), // Unreachable in valid code + Expr::Invalid(_) => err_other(), + } + } + + fn infer_array_lit( + &self, + n: &ArrayLit, + as_const: bool, + ) -> Result, ExprInferFailCause> { + if !as_const { + // Can not infer array types in non-const context, because narrowing would require type information + Err(ExprInferFailCause::ArrayWithoutAsConst { + expr: self.source_range_to_range(n.range()), + }) + } else { + let mut elem_types = vec![]; + + for elem in &n.elems { + match elem { + Some(expr) => { + if let Some(span) = expr.spread { + return Err(ExprInferFailCause::ArraySpread { + dot3_token: self.source_range_to_range(span.range()), + }); + } + let ty = self.infer_expr(&expr.expr, as_const, None)?; + elem_types.push(TsTupleElement { + span: expr.expr.span(), + ty, + label: None, + }); + } + None => elem_types.push(TsTupleElement { + span: DUMMY_SP, + ty: Box::new(ts_keyword_type( + TsKeywordTypeKind::TsUndefinedKeyword, + )), + label: None, + }), + } + } + + Ok(Box::new(TsType::TsTypeOperator(TsTypeOperator { + span: DUMMY_SP, + op: TsTypeOperatorOp::ReadOnly, + type_ann: Box::new(TsType::TsTupleType(TsTupleType { + span: n.span(), + elem_types, + })), + }))) + } + } + + // Infer a type from an expression in a `const x = ...` context. + pub fn infer_expr_in_const_pos( + &mut self, + expr: &Expr, + ident_range: Option, + ) -> Result, ExprInferFailCause> { + match expr { + Expr::Paren(n) => self.infer_expr_in_const_pos(&n.expr, ident_range), + Expr::TsSatisfies(n) => { + self.infer_expr_in_const_pos(&n.expr, ident_range) + } + Expr::Seq(n) => { + self.infer_expr_in_const_pos(n.exprs.last().unwrap(), ident_range) + } + Expr::Assign(n) => self.infer_expr_in_const_pos(&n.right, ident_range), + + Expr::Lit(lit) => Ok(Box::new(lit_to_ts_type_const(lit))), + Expr::Tpl(tpl) => self.infer_tpl_const(tpl), + + Expr::Call(n) + if is_call_expr_symbol_create( + n, + self.parsed_source.unresolved_context(), + ) => + { + Ok(Box::new(TsType::TsTypeOperator(TsTypeOperator { + span: DUMMY_SP, + op: TsTypeOperatorOp::Unique, + type_ann: Box::new(ts_keyword_type( + TsKeywordTypeKind::TsSymbolKeyword, + )), + }))) + } + + _ => self.infer_expr(expr, false, ident_range), + } + } + + fn infer_tpl_const( + &self, + tpl: &Tpl, + ) -> Result, ExprInferFailCause> { + if tpl.exprs.is_empty() { + let quasi = tpl.quasis.first().unwrap(); + Ok(Box::new(ts_lit_type(TsLit::Str(Str { + span: quasi.span, + value: quasi.cooked.clone().unwrap(), + raw: None, + })))) + } else { + Err(ExprInferFailCause::ExprInTemplateLiteral { + expr: self.source_range_to_range(tpl.exprs.first().unwrap().range()), + }) + } + } + + fn infer_object_lit( + &self, + n: &ObjectLit, + as_const: bool, + ) -> Result, ExprInferFailCause> { + let mut members = vec![]; + for prop in &n.props { + match prop { + PropOrSpread::Prop(prop) => match prop.as_ref() { + Prop::KeyValue(kv) => { + let (key, computed) = prop_name_to_ts_key(&kv.key); + let type_ann = + self.infer_expr(&kv.value, as_const, Some(key.range()))?; + members.push(TsTypeElement::TsPropertySignature( + TsPropertySignature { + span: kv.span(), + key, + computed, + type_ann: Some(Box::new(TsTypeAnn { + span: kv.value.span(), + type_ann, + })), + readonly: as_const, + optional: false, + // TODO: remove after https://github.com/swc-project/swc/pull/8955 lands + init: None, + params: vec![], + type_params: None, + }, + )); + } + Prop::Getter(getter) => { + let (key, computed) = prop_name_to_ts_key(&getter.key); + if getter.type_ann.is_none() { + // TODO(lucacasonato): if we know the type of the setter, use that + + let body = getter.body.as_ref().unwrap(); + let res = self.infer_function_body_block_stmt( + body, + FunctionKind::Getter, + /* is async */ false, + ); + match res { + Ok(ty) => members.push(TsTypeElement::TsGetterSignature( + TsGetterSignature { + span: getter.span(), + key, + computed, + type_ann: Some(Box::new(TsTypeAnn { + span: getter.span(), + type_ann: ty, + })), + readonly: false, + optional: false, + }, + )), + Err(cause) => { + return Err(ExprInferFailCause::ObjectGetter { + key: self.source_range_to_range(getter.key.range()), + cause: Box::new(FunctionInferFailCause::ReturnType { + cause: Box::new(cause), + }), + }) + } + } + } + } + Prop::Setter(setter) => { + let (key, computed) = prop_name_to_ts_key(&setter.key); + // TODO(lucacasonato): if we know the type of the setter, use that + + let param = + self + .infer_fn_param(&*setter.param, false) + .map_err(|cause| ExprInferFailCause::ObjectSetter { + key: self.source_range_to_range(setter.key.range()), + cause: Box::new(cause), + })?; + + members.push(TsTypeElement::TsSetterSignature(TsSetterSignature { + span: setter.span(), + key, + computed, + param, + readonly: false, + optional: false, + })); + } + Prop::Method(n) => { + let (key, computed) = prop_name_to_ts_key(&n.key); + + let return_type = + self.infer_fn_return_type(&n.function).map_err(|cause| { + ExprInferFailCause::ObjectMethod { + key: self.source_range_to_range(n.key.range()), + cause: Box::new(FunctionInferFailCause::ReturnType { + cause: Box::new(cause), + }), + } + })?; + let params = self + .infer_fn_params(n.function.params.iter().map(|p| &p.pat)) + .map_err(|cause| ExprInferFailCause::ObjectMethod { + key: self.source_range_to_range(n.key.range()), + cause: Box::new(cause), + })?; + + members.push(TsTypeElement::TsMethodSignature(TsMethodSignature { + span: n.span(), + key, + computed, + params, + type_ann: Some(return_type), + type_params: n.function.type_params.clone(), + readonly: false, + optional: false, + })); + } + Prop::Shorthand(n) => { + return Err(ExprInferFailCause::ObjectLitShorthand { + key: self.source_range_to_range(n.range()), + }) + } + Prop::Assign(_) => unreachable!("not valid on object literal"), + }, + PropOrSpread::Spread(n) => { + return Err(ExprInferFailCause::ObjectLitSpread { + dot3_token: self.source_range_to_range(n.dot3_token.range()), + }) + } + } + } + + let obj_literal = Box::new(TsType::TsTypeLit(TsTypeLit { + span: Default::default(), + members, + })); + + if as_const { + Ok(Box::new(TsType::TsTypeOperator(TsTypeOperator { + span: DUMMY_SP, + op: TsTypeOperatorOp::ReadOnly, + type_ann: obj_literal, + }))) + } else { + Ok(obj_literal) + } + } + + pub fn infer_function_body_block_stmt( + &self, + body: &BlockStmt, + function_kind: FunctionKind, + is_async: bool, + ) -> Result, ReturnTypeInferFailCause> { + let analysis = analyze_return_stmts_in_function_body(body); + match (analysis, function_kind) { + (_, FunctionKind::Setter) => unreachable!(), + (ReturnStatementAnalysis::None, FunctionKind::DeclarationLike) + | (ReturnStatementAnalysis::Void, FunctionKind::DeclarationLike) + | (ReturnStatementAnalysis::Void, FunctionKind::ExpressionLike) => { + Ok(void_or_promise_void(is_async)) + } + (ReturnStatementAnalysis::None, FunctionKind::ExpressionLike) => { + Err(ReturnTypeInferFailCause::NoReturnStmt { is_async }) + } + (ReturnStatementAnalysis::Single(n), _) => { + let expr = n.arg.as_ref().unwrap(); + match self.infer_expr(expr, /* as const */ false, None) { + Ok(ty) => Ok(ty), + Err(cause) => Err(ReturnTypeInferFailCause::ReturnStmtValue { + return_keyword: self.source_range_to_range(SourceRange { + start: n.span.start(), + end: n.span.start() + 6, + }), + cause: Box::new(cause), + }), + } + } + (ReturnStatementAnalysis::None, FunctionKind::Getter) + | (ReturnStatementAnalysis::Void, FunctionKind::Getter) => { + Err(ReturnTypeInferFailCause::NoValueReturnStmt) + } + (ReturnStatementAnalysis::Multiple, _) => { + Err(ReturnTypeInferFailCause::MultipleReturnStmts) + } + } + } + + fn infer_fn( + &self, + function: &Function, + ) -> Result, FunctionInferFailCause> { + let return_type = self.infer_fn_return_type(function).map_err(|cause| { + FunctionInferFailCause::ReturnType { + cause: Box::new(cause), + } + })?; + + let param_pats = function.params.iter().map(|param| ¶m.pat); + let params = self.infer_fn_params(param_pats)?; + + Ok(Box::new(TsType::TsFnOrConstructorType( + TsFnOrConstructorType::TsFnType(TsFnType { + span: function.span, + params, + type_ann: return_type, + type_params: function.type_params.clone(), + }), + ))) + } + + fn infer_fn_return_type( + &self, + function: &Function, + ) -> Result, ReturnTypeInferFailCause> { + let return_type = match &function.return_type { + Some(ty) => ty.clone(), + None => { + if function.is_generator { + return Err(ReturnTypeInferFailCause::IsGenerator); + } + + let body = function.body.as_ref().unwrap(); + let type_ann = self.infer_function_body_block_stmt( + body, + FunctionKind::ExpressionLike, + function.is_async, + )?; + + Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann, + }) + } + }; + Ok(return_type) + } + + fn infer_fn_params( + &self, + param_pats: impl Iterator, + ) -> Result, FunctionInferFailCause> { + let mut is_previous_optional = false; + let mut params = vec![]; + for pat in param_pats { + let optional = is_param_pat_optional(pat); + if !optional && is_previous_optional { + return Err(FunctionInferFailCause::RequiredParamAfterOptional { + pat: self.source_range_to_range(pat.range()), + }); + } + is_previous_optional = optional; + let param = self.infer_fn_param(&pat, optional)?; + params.push(param) + } + Ok(params) + } + + fn infer_fn_param( + &self, + pat: &Pat, + optional: bool, + ) -> Result { + let (pat, default_value) = match &*pat { + Pat::Assign(assign) => (&*assign.left, Some(&assign.right)), + _ => (pat, None), + }; + + let range = pat.range(); + + let mut type_ann = match pat { + Pat::Ident(n) => n.type_ann.clone(), + Pat::Array(n) => n.type_ann.clone(), + Pat::Object(n) => n.type_ann.clone(), + Pat::Rest(n) => n.type_ann.clone(), + Pat::Assign(_) => unreachable!(), + Pat::Expr(_) => unreachable!(), + Pat::Invalid(_) => unreachable!(), + }; + + if type_ann.is_none() { + if let Some(default_value) = default_value { + match self.infer_expr(default_value, false, None) { + Ok(ty) => { + type_ann = Some(Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann: ty, + })) + } + Err(cause) => { + return Err(FunctionInferFailCause::ParamType { + pat: self.source_range_to_range(range), + cause: Some(Box::new(cause)), + }); + } + }; + } else { + return Err(FunctionInferFailCause::ParamType { + pat: self.source_range_to_range(range), + cause: None, + }); + } + } + + Ok(pat_to_ts_fn_param(pat, type_ann, optional)) + } + + fn infer_arrow( + &self, + arrow: &ArrowExpr, + ) -> Result, FunctionInferFailCause> { + let params = self.infer_fn_params(arrow.params.iter())?; + + let return_type = match &arrow.return_type { + Some(ty) => ty.clone(), + None => { + if arrow.is_generator { + return Err(FunctionInferFailCause::ReturnType { + cause: Box::new(ReturnTypeInferFailCause::IsGenerator), + }); + } + + let type_ann = match &*arrow.body { + BlockStmtOrExpr::BlockStmt(body) => self + .infer_function_body_block_stmt( + body, + FunctionKind::ExpressionLike, + arrow.is_async, + ) + .map_err(|cause| FunctionInferFailCause::ReturnType { + cause: Box::new(cause), + })?, + BlockStmtOrExpr::Expr(expr) => self + .infer_expr(expr, false, None) + .map_err(|cause| FunctionInferFailCause::ReturnType { + cause: Box::new(ReturnTypeInferFailCause::ArrowExpressionValue { + cause: Box::new(cause), + }), + })?, + }; + + Box::new(TsTypeAnn { + span: DUMMY_SP, + type_ann, + }) + } + }; + + Ok(Box::new(TsType::TsFnOrConstructorType( + TsFnOrConstructorType::TsFnType(TsFnType { + span: arrow.span, + params, + type_ann: return_type, + type_params: arrow.type_params.clone(), + }), + ))) + } + + pub fn ensure_valid_type_ann( + &self, + ty: &TsType, + ) -> Result<(), ExprInferFailCause> { + struct Visitor<'a> { + root_symbol: &'a RootSymbol<'a>, + es_module_info: &'a EsModuleInfo, + invalid_range: Option, + } + + impl Visit for Visitor<'_> { + fn visit_ts_entity_name(&mut self, n: &TsEntityName) { + let (id, parts) = ts_entity_name_to_parts(n); + + let dep = SymbolNodeDep::QualifiedId(id, parts); + + let entries = self + .root_symbol + .resolve_symbol_dep(ModuleInfoRef::Esm(self.es_module_info), &dep); + + for entry in entries { + match entry { + ResolvedSymbolDepEntry::Path(DefinitionPathNode::Resolved(_)) + | ResolvedSymbolDepEntry::ImportType(_) => { + // valid + } + ResolvedSymbolDepEntry::Path(DefinitionPathNode::Unresolved(_)) => { + self.invalid_range = Some(n.range()); + } + } + } + } + } + + let mut visitor = Visitor { + es_module_info: self.module_info, + root_symbol: self.root_symbol, + invalid_range: None, + }; + ty.visit_with(&mut visitor); + match visitor.invalid_range { + Some(range) => Err(ExprInferFailCause::LocalReference { + ident: self.source_range_to_range(range), + }), + None => Ok(()), + } + } +} + +fn pat_to_ts_fn_param( + pat: &Pat, + type_ann: Option>, + optional: bool, +) -> TsFnParam { + match pat { + Pat::Ident(n) => TsFnParam::Ident(BindingIdent { + id: Ident { + span: n.span, + sym: n.sym.clone(), + optional, + }, + type_ann, + }), + pat @ Pat::Array(_) => { + let mut new_pat = pat.clone(); + clean_pat_for_ts_fn_param(&mut new_pat); + let Pat::Array(mut n) = new_pat else { + unreachable!() + }; + n.optional = optional; + n.type_ann = type_ann; + TsFnParam::Array(n) + } + pat @ Pat::Object(_) => { + let mut new_pat = pat.clone(); + clean_pat_for_ts_fn_param(&mut new_pat); + let Pat::Object(mut n) = new_pat else { + unreachable!() + }; + n.optional = optional; + n.type_ann = type_ann; + TsFnParam::Object(n) + } + pat @ Pat::Rest(_) => { + let mut new_pat = pat.clone(); + clean_pat_for_ts_fn_param(&mut new_pat); + let Pat::Rest(mut n) = new_pat else { + unreachable!() + }; + n.type_ann = type_ann; + TsFnParam::Rest(n) + } + Pat::Assign(p) => pat_to_ts_fn_param(&p.left, type_ann, optional), + Pat::Invalid(_) => unreachable!(), + Pat::Expr(_) => unreachable!(), + } +} + +fn clean_pat_for_ts_fn_param(p: &mut Pat) { + match &mut *p { + Pat::Assign(n) => { + *p = *n.left.clone(); + clean_pat_for_ts_fn_param(p); + } + Pat::Array(n) => { + n.optional = false; + n.type_ann = None; + for elem in &mut n.elems { + if let Some(elem) = elem { + clean_pat_for_ts_fn_param(elem); + } + } + } + Pat::Object(n) => { + n.optional = false; + n.type_ann = None; + for prop in &mut n.props { + match prop { + ObjectPatProp::KeyValue(p) => clean_pat_for_ts_fn_param(&mut p.value), + ObjectPatProp::Assign(p) => p.value = None, + ObjectPatProp::Rest(p) => clean_pat_for_ts_fn_param(&mut p.arg), + } + } + } + Pat::Rest(n) => { + n.type_ann = None; + clean_pat_for_ts_fn_param(&mut n.arg) + } + Pat::Ident(n) => { + n.id.optional = false; + n.type_ann = None; + } + Pat::Invalid(_) | Pat::Expr(_) => unreachable!(), + } +} diff --git a/src/lib.rs b/src/lib.rs index fc7980ef3..ff532e285 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,9 @@ pub mod packages; pub mod source; mod text_encoding; +#[cfg(any(feature = "symbols", feature = "fast_check"))] +mod swc_helpers; + use source::FileSystem; use source::JsrUrlProvider; use source::NpmResolver; diff --git a/src/swc_helpers.rs b/src/swc_helpers.rs new file mode 100644 index 000000000..2564b0772 --- /dev/null +++ b/src/swc_helpers.rs @@ -0,0 +1,145 @@ +// Copyright 2018-2024 the Deno authors. MIT license. + +use std::ops::ControlFlow; + +use deno_ast::swc::ast::BlockStmt; +use deno_ast::swc::ast::Id; +use deno_ast::swc::ast::ReturnStmt; +use deno_ast::swc::ast::Stmt; +use deno_ast::swc::ast::TsEntityName; +use deno_ast::swc::ast::TsQualifiedName; + +pub enum FunctionKind { + /// function declarations, class method declarations (both class decl and class expr) + DeclarationLike, + /// function expressions, arrow functions, object method shorthand properties + ExpressionLike, + /// getters, both on classes and object literals + Getter, + /// setters, both on classes and object literals + Setter, +} + +#[derive(Debug)] +pub enum ReturnStatementAnalysis { + /// There are no return statements in the function body. + None, + /// There are only return statements without arguments in the function body, + /// or if the function body is empty. + Void, + /// There is only a single return statement in the function body, and it has + /// an argument. + Single(ReturnStmt), + /// There are multiple return statements in the function body, and at least + /// one of them has an argument. + Multiple, +} + +pub fn analyze_return_stmts_in_function_body( + body: &BlockStmt, +) -> ReturnStatementAnalysis { + if body.stmts.is_empty() { + ReturnStatementAnalysis::Void + } else { + let mut analysis = ReturnStatementAnalysis::None; + analyze_return_stmts_from_stmts(&body.stmts, &mut analysis); + analysis + } +} + +fn analyze_return_stmts_from_stmts( + stmts: &[Stmt], + analysis: &mut ReturnStatementAnalysis, +) -> ControlFlow<(), ()> { + for stmt in stmts { + analyze_return_stmts_from_stmt(stmt, analysis)?; + } + ControlFlow::Continue(()) +} + +fn analyze_return_stmts_from_stmt( + stmt: &Stmt, + analysis: &mut ReturnStatementAnalysis, +) -> ControlFlow<(), ()> { + match stmt { + Stmt::Block(n) => analyze_return_stmts_from_stmts(&n.stmts, analysis), + Stmt::With(n) => analyze_return_stmts_from_stmt(&n.body, analysis), + Stmt::Return(n) => { + match (&n.arg, &*analysis) { + (None, ReturnStatementAnalysis::None) => { + *analysis = ReturnStatementAnalysis::Void; + } + (None, ReturnStatementAnalysis::Void) => {} + (Some(_), ReturnStatementAnalysis::None) + | (Some(_), ReturnStatementAnalysis::Void) => { + *analysis = ReturnStatementAnalysis::Single(n.clone()); + } + (_, ReturnStatementAnalysis::Single(_)) => { + *analysis = ReturnStatementAnalysis::Multiple; + return ControlFlow::Break(()); + } + (_, ReturnStatementAnalysis::Multiple) => unreachable!(), // we break early when analysis is Multiple + } + ControlFlow::Continue(()) + } + Stmt::Labeled(n) => analyze_return_stmts_from_stmt(&n.body, analysis), + Stmt::If(n) => analyze_return_stmts_from_stmt(&n.cons, analysis), + Stmt::Switch(n) => { + for case in &n.cases { + analyze_return_stmts_from_stmts(&case.cons, analysis)?; + } + ControlFlow::Continue(()) + } + Stmt::Try(n) => { + analyze_return_stmts_from_stmts(&n.block.stmts, analysis)?; + if let Some(n) = &n.handler { + analyze_return_stmts_from_stmts(&n.body.stmts, analysis)?; + } + if let Some(n) = &n.finalizer { + analyze_return_stmts_from_stmts(&n.stmts, analysis)?; + } + ControlFlow::Continue(()) + } + Stmt::While(n) => analyze_return_stmts_from_stmt(&n.body, analysis), + Stmt::DoWhile(n) => analyze_return_stmts_from_stmt(&n.body, analysis), + Stmt::For(n) => analyze_return_stmts_from_stmt(&n.body, analysis), + Stmt::ForIn(n) => analyze_return_stmts_from_stmt(&n.body, analysis), + Stmt::ForOf(n) => analyze_return_stmts_from_stmt(&n.body, analysis), + Stmt::Break(_) + | Stmt::Continue(_) + | Stmt::Throw(_) + | Stmt::Debugger(_) + | Stmt::Decl(_) + | Stmt::Expr(_) + | Stmt::Empty(_) => ControlFlow::Continue(()), + } +} + +pub fn ts_entity_name_to_parts( + entity_name: &TsEntityName, +) -> (Id, Vec) { + match entity_name { + TsEntityName::TsQualifiedName(qualified_name) => { + ts_qualified_name_parts(qualified_name) + } + TsEntityName::Ident(ident) => (ident.to_id(), Vec::new()), + } +} + +pub fn ts_qualified_name_parts( + mut qualified_name: &TsQualifiedName, +) -> (Id, Vec) { + let mut parts = Vec::new(); + loop { + parts.push(qualified_name.right.sym.to_string()); + match &qualified_name.left { + TsEntityName::TsQualifiedName(n) => { + qualified_name = n; + } + TsEntityName::Ident(n) => { + parts.reverse(); + return (n.to_id(), parts); + } + } + } +} diff --git a/src/symbols/analyzer.rs b/src/symbols/analyzer.rs index a8fc4ee9a..3ce0ce19a 100644 --- a/src/symbols/analyzer.rs +++ b/src/symbols/analyzer.rs @@ -10,6 +10,8 @@ use deno_ast::swc::ast::*; use deno_ast::swc::atoms::Atom; use deno_ast::swc::utils::find_pat_ids; use deno_ast::swc::utils::is_valid_ident; +use deno_ast::swc::visit::Visit; +use deno_ast::swc::visit::VisitWith as _; use deno_ast::ModuleSpecifier; use deno_ast::ParsedSource; use deno_ast::SourceRange; @@ -18,6 +20,10 @@ use deno_ast::SourceTextInfo; use indexmap::IndexMap; use indexmap::IndexSet; +use crate::swc_helpers::analyze_return_stmts_in_function_body; +use crate::swc_helpers::ts_entity_name_to_parts; +use crate::swc_helpers::FunctionKind; +use crate::swc_helpers::ReturnStatementAnalysis; use crate::JsModule; use crate::JsonModule; use crate::ModuleGraph; @@ -34,7 +40,6 @@ use super::cross_module::DefinitionOrUnresolved; use super::cross_module::DefinitionPathNode; use super::cross_module::ModuleExports; use super::dep_analyzer::ResolveDepsMode; -use super::swc_helpers::ts_entity_name_to_parts; use super::ResolvedSymbolDepEntry; use super::SymbolNodeDep; @@ -368,6 +373,7 @@ impl std::fmt::Debug for SymbolNode { SymbolNodeInner::FnDecl(d) => { d.value().text_fast(d.source.text_info()).to_string() } + SymbolNodeInner::Param { ident, .. } => ident.sym.to_string(), SymbolNodeInner::TsEnum(d) => { d.value().text_fast(d.source.text_info()).to_string() } @@ -492,6 +498,9 @@ impl SymbolNode { SymbolNodeInner::FnDecl(n) => { Some((SymbolNodeRef::FnDecl(n.value()), n.source())) } + SymbolNodeInner::Param { ident, source } => { + Some((SymbolNodeRef::Param(ident), source)) + } SymbolNodeInner::TsEnum(n) => { Some((SymbolNodeRef::TsEnum(n.value()), n.source())) } @@ -577,6 +586,7 @@ enum SymbolNodeInner { ExportDefaultDecl(NodeRefBox), ExportDefaultExpr(NodeRefBox), FnDecl(NodeRefBox), + Param { ident: Ident, source: ParsedSource }, TsEnum(NodeRefBox), TsNamespace(NodeRefBox), TsTypeAlias(NodeRefBox), @@ -617,6 +627,7 @@ pub enum SymbolNodeRef<'a> { ExportDefaultExpr(&'a ExportDefaultExpr), ClassDecl(&'a ClassDecl), FnDecl(&'a FnDecl), + Param(&'a Ident), TsEnum(&'a TsEnumDecl), TsInterface(&'a TsInterfaceDecl), TsNamespace(&'a TsModuleDecl), @@ -715,6 +726,7 @@ impl<'a> SymbolNodeRef<'a> { }, Self::ExportDefaultExpr(_) => None, Self::FnDecl(n) => Some(Cow::Borrowed(&n.ident.sym)), + Self::Param(n) => Some(Cow::Borrowed(&n.sym)), Self::TsEnum(n) => Some(Cow::Borrowed(&n.id.sym)), Self::TsInterface(n) => Some(Cow::Borrowed(&n.id.sym)), Self::TsNamespace(n) => { @@ -829,7 +841,8 @@ impl<'a> SymbolNodeRef<'a> { | SymbolNodeRef::ClassDecl(_) | SymbolNodeRef::TsEnum(_) | SymbolNodeRef::TsInterface(_) => true, - SymbolNodeRef::TsTypeAlias(_) + SymbolNodeRef::Param(_) + | SymbolNodeRef::TsTypeAlias(_) | SymbolNodeRef::ExportDefaultExpr(_) | SymbolNodeRef::Var(..) | SymbolNodeRef::UsingVar(..) @@ -859,6 +872,7 @@ impl<'a> SymbolNodeRef<'a> { SymbolNodeRef::Module(_) | SymbolNodeRef::ClassDecl(_) | SymbolNodeRef::FnDecl(_) + | SymbolNodeRef::Param(_) | SymbolNodeRef::TsEnum(_) | SymbolNodeRef::TsInterface(_) | SymbolNodeRef::TsNamespace(_) @@ -902,6 +916,7 @@ impl<'a> SymbolNodeRef<'a> { | SymbolNodeRef::ClassParamProp(_) | SymbolNodeRef::Constructor(_) | SymbolNodeRef::ExpandoProperty(..) + | SymbolNodeRef::Param(_) | SymbolNodeRef::TsIndexSignature(_) | SymbolNodeRef::TsCallSignatureDecl(_) | SymbolNodeRef::TsConstructSignatureDecl(_) @@ -921,6 +936,7 @@ impl<'a> SymbolNodeRef<'a> { | SymbolNodeRef::ExportDefaultDecl(_) | SymbolNodeRef::ExportDefaultExpr(_) | SymbolNodeRef::FnDecl(_) + | SymbolNodeRef::Param(_) | SymbolNodeRef::TsEnum(_) | SymbolNodeRef::TsInterface(_) | SymbolNodeRef::TsNamespace(_) @@ -952,6 +968,7 @@ impl<'a> SymbolNodeRef<'a> { | SymbolNodeRef::ExportDefaultDecl(_) | SymbolNodeRef::ExportDefaultExpr(_) | SymbolNodeRef::FnDecl(_) + | SymbolNodeRef::Param(_) | SymbolNodeRef::TsEnum(_) | SymbolNodeRef::TsInterface(_) | SymbolNodeRef::TsNamespace(_) @@ -1335,6 +1352,16 @@ impl Symbol { .map(|n| n.is_private_member()) .unwrap_or(false) } + + /// If the symbol is a parameter. + pub fn is_param(&self) -> bool { + self + .decls() + .first() + .and_then(|d| d.maybe_node()) + .map(|n| matches!(n, SymbolNodeRef::Param(_))) + .unwrap_or(false) + } } /// A unique identifier for a symbol, which consists of the module id and symbol id. @@ -1989,6 +2016,11 @@ impl<'a> SymbolFiller<'a> { ); module_symbol.add_export(n.ident.sym.to_string(), symbol_id); module_symbol.add_child_id(symbol_id); + self.fill_function( + symbol_id, + &n.function, + FunctionKind::DeclarationLike, + ); } Decl::Var(n) => { for decl in &n.decls { @@ -2015,6 +2047,7 @@ impl<'a> SymbolFiller<'a> { module_symbol.add_child_id(symbol_id); module_symbol.add_export(export_name, symbol_id); } + self.fill_var_decl(module_symbol.symbol_id(), decl); } } Decl::TsInterface(n) => { @@ -2261,8 +2294,12 @@ impl<'a> SymbolFiller<'a> { DefaultDecl::Class(n) => { self.fill_class(symbol, &n.class); } - DefaultDecl::Fn(_) => { - // nothing to fill + DefaultDecl::Fn(n) => { + self.fill_function( + symbol.symbol_id(), + &n.function, + FunctionKind::DeclarationLike, + ); } DefaultDecl::TsInterfaceDecl(n) => { self.fill_ts_interface(symbol, n) @@ -2394,6 +2431,11 @@ impl<'a> SymbolFiller<'a> { if decls_are_exports { module_symbol.add_export(n.ident.sym.to_string(), symbol_id); } + self.fill_function( + symbol_id, + &n.function, + FunctionKind::DeclarationLike, + ); } Decl::Var(var_decl) => { for decl in &var_decl.decls { @@ -2419,6 +2461,7 @@ impl<'a> SymbolFiller<'a> { module_symbol.add_export(export_name, symbol_id); } } + self.fill_var_decl(module_symbol.symbol_id(), decl); } } Decl::TsInterface(n) => { @@ -2534,6 +2577,7 @@ impl<'a> SymbolFiller<'a> { module_symbol.add_export(export_name, symbol_id); } } + self.fill_var_decl(module_symbol.symbol_id(), decl); } } }; @@ -2620,6 +2664,11 @@ impl<'a> SymbolFiller<'a> { } fn fill_class(&self, symbol: &SymbolMut, n: &Class) { + if let Some(type_params) = n.type_params.as_ref() { + for param in &type_params.params { + self.add_param(symbol.symbol_id(), param.name.clone()); + } + } self.fill_ts_class_members(symbol, &n.body); } @@ -2732,33 +2781,49 @@ impl<'a> SymbolFiller<'a> { for member in members { match member { ClassMember::Constructor(ctor) => { - self.create_symbol_member_or_export( + let ctor_symbol = self.create_symbol_member_or_export( symbol, SymbolNodeRef::Constructor(ctor), ); for param in &ctor.params { - if let ParamOrTsParamProp::TsParamProp(prop) = param { - self.create_symbol_member_or_export( - symbol, - SymbolNodeRef::ClassParamProp(prop), - ); + match param { + ParamOrTsParamProp::TsParamProp(prop) => { + self.create_symbol_member_or_export( + symbol, + SymbolNodeRef::ClassParamProp(prop), + ); + } + ParamOrTsParamProp::Param(param) => self.fill_fn_params( + ctor_symbol.symbol_id(), + [¶m.pat].into_iter(), + ), } } } ClassMember::Method(method) => { - self.create_symbol_member_or_export( + let method_symbol = self.create_symbol_member_or_export( symbol, SymbolNodeRef::ClassMethod(method), ); + self.fill_function( + method_symbol.symbol_id(), + &method.function, + FunctionKind::DeclarationLike, + ); } ClassMember::PrivateMethod(_) => { // todo(dsherret): add private methods } ClassMember::ClassProp(prop) => { - self.create_symbol_member_or_export( + let prop_symbol = self.create_symbol_member_or_export( symbol, SymbolNodeRef::ClassProp(prop), ); + if prop.type_ann.is_none() { + if let Some(value) = &prop.value { + self.fill_expr(prop_symbol.symbol_id(), value); + } + } } ClassMember::PrivateProp(_) => { // todo(dsherret): add private properties @@ -2883,6 +2948,7 @@ impl<'a> SymbolFiller<'a> { | SymbolNodeRef::ExportDefaultDecl(_) | SymbolNodeRef::ExportDefaultExpr(_) | SymbolNodeRef::FnDecl(_) + | SymbolNodeRef::Param(_) | SymbolNodeRef::TsEnum(_) | SymbolNodeRef::TsInterface(_) | SymbolNodeRef::TsNamespace(_) @@ -2978,4 +3044,196 @@ impl<'a> SymbolFiller<'a> { } None } + + fn fill_function( + &self, + symbol_id: SymbolId, + n: &Function, + fn_kind: FunctionKind, + ) { + if let Some(type_params) = n.type_params.as_ref() { + for param in &type_params.params { + self.add_param(symbol_id, param.name.clone()); + } + } + self.fill_fn_params(symbol_id, n.params.iter().map(|p| &p.pat)); + if let Some(type_ann) = n.return_type.as_ref() { + self.fill_ts_type(symbol_id, &type_ann.type_ann); + } else if let Some(body) = n.body.as_ref() { + self.fill_fn_body(symbol_id, body, fn_kind); + } + } + + fn fill_arrow_expr(&self, symbol_id: SymbolId, n: &ArrowExpr) { + if let Some(type_params) = n.type_params.as_ref() { + for param in &type_params.params { + self.add_param(symbol_id, param.name.clone()); + } + } + self.fill_fn_params(symbol_id, n.params.iter()); + if let Some(type_ann) = n.return_type.as_ref() { + self.fill_ts_type(symbol_id, &type_ann.type_ann); + } else { + match &*n.body { + BlockStmtOrExpr::BlockStmt(block) => { + self.fill_fn_body(symbol_id, block, FunctionKind::ExpressionLike); + } + BlockStmtOrExpr::Expr(expr) => { + self.fill_expr(symbol_id, expr); + } + } + } + } + + fn fill_fn_params<'b>( + &self, + symbol_id: SymbolId, + params: impl Iterator, + ) { + for param in params { + let (pat, default_value) = match param { + Pat::Assign(pat) => (&*pat.left, Some(&pat.right)), + _ => (param, None), + }; + + let type_ann = match pat { + Pat::Ident(n) => n.type_ann.as_ref(), + Pat::Array(n) => n.type_ann.as_ref(), + Pat::Object(n) => n.type_ann.as_ref(), + Pat::Rest(n) => n.type_ann.as_ref(), + Pat::Invalid(_) | Pat::Expr(_) | Pat::Assign(_) => unreachable!(), + }; + + if let Some(type_ann) = type_ann { + self.fill_ts_type(symbol_id, &type_ann.type_ann); + } else if let Some(default_value) = default_value { + self.fill_expr(symbol_id, default_value); + } + + for ident in find_pat_ids::<_, Ident>(pat) { + self.add_param(symbol_id, ident); + } + } + } + + fn add_param(&self, parent_id: SymbolId, ident: Ident) { + let range = ident.range(); + self.builder.ensure_symbol_for_swc_id( + ident.to_id(), + SymbolDecl::new( + SymbolDeclKind::Definition(SymbolNode(SymbolNodeInner::Param { + ident, + source: self.source.clone(), + })), + range, + ), + parent_id, + ); + } + + fn fill_ts_type(&self, symbol_id: SymbolId, type_ann: &TsType) { + struct TsTypeVisitor { + idents: I, + } + impl Visit for TsTypeVisitor { + fn visit_ts_infer_type(&mut self, n: &TsInferType) { + (self.idents)(&n.type_param.name); + } + + fn visit_ts_type_param(&mut self, n: &TsTypeParam) { + (self.idents)(&n.name); + } + + fn visit_ts_fn_param(&mut self, n: &TsFnParam) { + match n { + TsFnParam::Ident(ident) => { + (self.idents)(&ident.id); + } + TsFnParam::Array(n) => { + for ident in find_pat_ids::<_, Ident>(n) { + (self.idents)(&ident); + } + } + TsFnParam::Rest(n) => { + for ident in find_pat_ids::<_, Ident>(n) { + (self.idents)(&ident); + } + } + TsFnParam::Object(n) => { + for ident in find_pat_ids::<_, Ident>(n) { + (self.idents)(&ident); + } + } + } + } + } + + let mut visitor = TsTypeVisitor { + idents: |ident| { + self.add_param(symbol_id, ident.clone()); + }, + }; + type_ann.visit_with(&mut visitor); + } + + fn fill_fn_body( + &self, + symbol_id: SymbolId, + body: &BlockStmt, + fn_kind: FunctionKind, + ) { + let analysis = analyze_return_stmts_in_function_body(body); + if let ( + FunctionKind::DeclarationLike | FunctionKind::ExpressionLike, + ReturnStatementAnalysis::Single(stmt), + ) = (fn_kind, analysis) + { + self.fill_expr(symbol_id, stmt.arg.as_ref().unwrap()); + } + } + + fn fill_expr(&self, symbol_id: SymbolId, expr: &Expr) { + struct ExprVisitor { + fn_exprs: F, + arrow_exprs: A, + } + impl Visit for ExprVisitor { + fn visit_fn_expr(&mut self, n: &FnExpr) { + (self.fn_exprs)(n); + } + fn visit_arrow_expr(&mut self, n: &ArrowExpr) { + (self.arrow_exprs)(n); + } + } + + let mut visitor = ExprVisitor { + fn_exprs: |n| { + self.fill_function( + symbol_id, + &n.function, + FunctionKind::ExpressionLike, + ); + }, + arrow_exprs: |n| { + self.fill_arrow_expr(symbol_id, n); + }, + }; + expr.visit_with(&mut visitor); + } + + fn fill_var_decl(&self, symbol_id: SymbolId, decl: &VarDeclarator) { + let type_ann = match &decl.name { + Pat::Ident(n) => n.type_ann.as_ref(), + Pat::Array(n) => n.type_ann.as_ref(), + Pat::Object(n) => n.type_ann.as_ref(), + Pat::Rest(_) | Pat::Invalid(_) | Pat::Expr(_) | Pat::Assign(_) => { + unreachable!() + } + }; + if let Some(type_ann) = type_ann { + self.fill_ts_type(symbol_id, &type_ann.type_ann); + } else if let Some(init) = decl.init.as_ref() { + self.fill_expr(symbol_id, init); + } + } } diff --git a/src/symbols/dep_analyzer.rs b/src/symbols/dep_analyzer.rs index c2867d953..b1db0492a 100644 --- a/src/symbols/dep_analyzer.rs +++ b/src/symbols/dep_analyzer.rs @@ -1,6 +1,8 @@ // Copyright 2018-2024 the Deno authors. MIT license. +use deno_ast::swc::ast::ArrowExpr; use deno_ast::swc::ast::BindingIdent; +use deno_ast::swc::ast::BlockStmtOrExpr; use deno_ast::swc::ast::Class; use deno_ast::swc::ast::DefaultDecl; use deno_ast::swc::ast::Expr; @@ -40,8 +42,10 @@ use deno_ast::swc::ast::VarDeclarator; use deno_ast::swc::visit::Visit; use deno_ast::swc::visit::VisitWith; -use super::swc_helpers::ts_entity_name_to_parts; -use super::swc_helpers::ts_qualified_name_parts; +use crate::swc_helpers::analyze_return_stmts_in_function_body; +use crate::swc_helpers::ts_entity_name_to_parts; +use crate::swc_helpers::ts_qualified_name_parts; + use super::ExportDeclRef; use super::SymbolNodeRef; @@ -127,6 +131,7 @@ impl DepsFiller { self.visit_expr(&n.expr); } SymbolNodeRef::FnDecl(n) => self.visit_function(&n.function), + SymbolNodeRef::Param(_) => {} SymbolNodeRef::TsEnum(n) => { self.visit_ts_enum_decl(n); } @@ -339,6 +344,55 @@ impl Visit for DepsFiller { } if let Some(return_type) = &n.return_type { self.visit_ts_type_ann(return_type); + } else if let Some(body) = &n.body { + match analyze_return_stmts_in_function_body(body) { + crate::swc_helpers::ReturnStatementAnalysis::Single(return_stmt) => { + if let Some(arg) = &return_stmt.arg { + let visited_type_assertion = self.visit_type_if_type_assertion(arg); + if !visited_type_assertion && self.mode.visit_exprs() { + self.visit_expr(arg); + } + } + } + _ => {} + } + } + } + + fn visit_arrow_expr(&mut self, n: &ArrowExpr) { + if let Some(type_params) = &n.type_params { + self.visit_ts_type_param_decl(type_params); + } + for param in &n.params { + self.visit_pat(param); + } + if let Some(return_type) = &n.return_type { + self.visit_ts_type_ann(return_type); + } else { + match &*n.body { + BlockStmtOrExpr::BlockStmt(body) => { + match analyze_return_stmts_in_function_body(body) { + crate::swc_helpers::ReturnStatementAnalysis::Single( + return_stmt, + ) => { + if let Some(arg) = &return_stmt.arg { + let visited_type_assertion = + self.visit_type_if_type_assertion(arg); + if !visited_type_assertion && self.mode.visit_exprs() { + self.visit_expr(arg); + } + } + } + _ => {} + } + } + BlockStmtOrExpr::Expr(expr) => { + let visited_type_assertion = self.visit_type_if_type_assertion(expr); + if !visited_type_assertion && self.mode.visit_exprs() { + self.visit_expr(expr); + } + } + } } } diff --git a/src/symbols/mod.rs b/src/symbols/mod.rs index 38361f7ef..7f6749697 100644 --- a/src/symbols/mod.rs +++ b/src/symbols/mod.rs @@ -35,4 +35,3 @@ mod analyzer; mod collections; mod cross_module; mod dep_analyzer; -mod swc_helpers; diff --git a/src/symbols/swc_helpers.rs b/src/symbols/swc_helpers.rs deleted file mode 100644 index 10d1685f7..000000000 --- a/src/symbols/swc_helpers.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2018-2024 the Deno authors. MIT license. - -use deno_ast::swc::ast::Id; -use deno_ast::swc::ast::TsEntityName; -use deno_ast::swc::ast::TsQualifiedName; - -pub fn ts_entity_name_to_parts( - entity_name: &TsEntityName, -) -> (Id, Vec) { - match entity_name { - TsEntityName::TsQualifiedName(qualified_name) => { - ts_qualified_name_parts(qualified_name) - } - TsEntityName::Ident(ident) => (ident.to_id(), Vec::new()), - } -} - -pub fn ts_qualified_name_parts( - mut qualified_name: &TsQualifiedName, -) -> (Id, Vec) { - let mut parts = Vec::new(); - loop { - parts.push(qualified_name.right.sym.to_string()); - match &qualified_name.left { - TsEntityName::TsQualifiedName(n) => { - qualified_name = n; - } - TsEntityName::Ident(n) => { - parts.reverse(); - return (n.to_id(), parts); - } - } - } -} diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs index af1fa7889..b250619c9 100644 --- a/tests/helpers/mod.rs +++ b/tests/helpers/mod.rs @@ -300,39 +300,41 @@ impl TestBuilder { } } - if let Some(parent_id) = symbol.parent_id() { - let parent_symbol = module.symbol(parent_id).unwrap(); - let has_child = - parent_symbol.child_ids().any(|id| id == symbol.symbol_id()); - let has_member = parent_symbol - .members() - .iter() - .any(|id| *id == symbol.symbol_id()); - let is_definition_decl = - symbol.decls().iter().all(|d| d.kind.is_definition()); - if is_definition_decl { - // ensure it's possible to go from a parent to its child - if !has_child && !has_member { + if !symbol.is_param() { + if let Some(parent_id) = symbol.parent_id() { + let parent_symbol = module.symbol(parent_id).unwrap(); + let has_child = + parent_symbol.child_ids().any(|id| id == symbol.symbol_id()); + let has_member = parent_symbol + .members() + .iter() + .any(|id| *id == symbol.symbol_id()); + let is_definition_decl = + symbol.decls().iter().all(|d| d.kind.is_definition()); + if is_definition_decl { + // ensure it's possible to go from a parent to its child + if !has_child && !has_member { + results.push(format!( + "Parent {:#?} does not have child {:#?}", + parent_symbol.symbol_id(), + symbol.symbol_id() + )); + } + } else if has_child || has_member { results.push(format!( - "Parent {:#?} does not have child {:#?}", + "Parent {:#?} should not have the child or member {:#?}", parent_symbol.symbol_id(), symbol.symbol_id() )); } - } else if has_child || has_member { - results.push(format!( - "Parent {:#?} should not have the child or member {:#?}", - parent_symbol.symbol_id(), - symbol.symbol_id() - )); - } - if has_child && has_member { - results.push(format!( - "Parent {:?} should not have both a child and a member {:?}", - parent_symbol.symbol_id(), - symbol.symbol_id() - )); + if has_child && has_member { + results.push(format!( + "Parent {:?} should not have both a child and a member {:?}", + parent_symbol.symbol_id(), + symbol.symbol_id() + )); + } } } diff --git a/tests/specs/graph/fast_check/cache__diagnostic.txt b/tests/specs/graph/fast_check/cache__diagnostic.txt index f8b337032..060782166 100644 --- a/tests/specs/graph/fast_check/cache__diagnostic.txt +++ b/tests/specs/graph/fast_check/cache__diagnostic.txt @@ -140,15 +140,21 @@ import 'jsr:@scope/a' } Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> https://jsr.io/@scope/a/1.0.0/c.ts:1:17 | 1 | export function add(a: number, b: number) { - | ^^^ this function is missing an explicit return type + | --- this function's return type could not be inferred + | + 2 | return Math.random(); + | ------ because the value returned here + | ------------- contains this expression, of which the type could not be inferred + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type == fast check cache == diff --git a/tests/specs/graph/fast_check/cache__diagnostic_deep.txt b/tests/specs/graph/fast_check/cache__diagnostic_deep.txt index 99551b31c..e872c8231 100644 --- a/tests/specs/graph/fast_check/cache__diagnostic_deep.txt +++ b/tests/specs/graph/fast_check/cache__diagnostic_deep.txt @@ -141,15 +141,21 @@ import 'jsr:@scope/a' } Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> https://jsr.io/@scope/a/1.0.0/c.ts:1:17 | 1 | export function add(a: number, b: number) { - | ^^^ this function is missing an explicit return type + | --- this function's return type could not be inferred + | + 2 | return Math.random(); + | ------ because the value returned here + | ------------- contains this expression, of which the type could not be inferred + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type == fast check cache == diff --git a/tests/specs/graph/fast_check/cache__diagnostic_multiple_exports.txt b/tests/specs/graph/fast_check/cache__diagnostic_multiple_exports.txt index dc972f177..67e0821be 100644 --- a/tests/specs/graph/fast_check/cache__diagnostic_multiple_exports.txt +++ b/tests/specs/graph/fast_check/cache__diagnostic_multiple_exports.txt @@ -162,27 +162,39 @@ import 'jsr:@scope/a/c' } Fast check https://jsr.io/@scope/a/1.0.0/c.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> https://jsr.io/@scope/a/1.0.0/a.ts:1:17 | 1 | export function add(a: number, b: number) { - | ^^^ this function is missing an explicit return type + | --- this function's return type could not be inferred + | + 2 | return Math.random(); + | ------ because the value returned here + | ------------- contains this expression, of which the type could not be inferred + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> https://jsr.io/@scope/a/1.0.0/a.ts:1:17 | 1 | export function add(a: number, b: number) { - | ^^^ this function is missing an explicit return type + | --- this function's return type could not be inferred + | + 2 | return Math.random(); + | ------ because the value returned here + | ------------- contains this expression, of which the type could not be inferred + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type == fast check cache == diff --git a/tests/specs/graph/fast_check/cache__diagnostic_then_nested_dep.txt b/tests/specs/graph/fast_check/cache__diagnostic_then_nested_dep.txt index 13d946b1a..9a3371978 100644 --- a/tests/specs/graph/fast_check/cache__diagnostic_then_nested_dep.txt +++ b/tests/specs/graph/fast_check/cache__diagnostic_then_nested_dep.txt @@ -174,15 +174,21 @@ jsr deps: { } Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> https://jsr.io/@scope/a/1.0.0/mod.ts:1:17 | 1 | export function add(a: number, b: number) { - | ^^^ this function is missing an explicit return type + | --- this function's return type could not be inferred + | + 2 | return Math.random(); + | ------ because the value returned here + | ------------- contains this expression, of which the type could not be inferred + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type Fast check https://jsr.io/@scope/b/1.0.0/mod.ts: diff --git a/tests/specs/graph/fast_check/class_member_ref_additional_prop_on_member.txt b/tests/specs/graph/fast_check/class_member_ref_additional_prop_on_member.txt index 750e64fe4..20b07d08a 100644 --- a/tests/specs/graph/fast_check/class_member_ref_additional_prop_on_member.txt +++ b/tests/specs/graph/fast_check/class_member_ref_additional_prop_on_member.txt @@ -67,10 +67,13 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: | 5 | class MyClass { | ^^^^^^^^^^^^^^^ + | 6 | member: string; | ^^^^^^^^^^^^^^^^^ + | 7 | } | ^ this is the reference + | = hint: extract the shared type to a type alias and reference the type alias instead info: the reference was too complex to be resolved by fast check diff --git a/tests/specs/graph/fast_check/class_member_ref_not_found.txt b/tests/specs/graph/fast_check/class_member_ref_not_found.txt index a8e47cf35..9f2f5b551 100644 --- a/tests/specs/graph/fast_check/class_member_ref_not_found.txt +++ b/tests/specs/graph/fast_check/class_member_ref_not_found.txt @@ -66,10 +66,13 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: | 4 | class Public1 { | ^^^^^^^^^^^^^^^ + | 5 | prop: string; | ^^^^^^^^^^^^^^^ + | 6 | } | ^ this is the reference + | = hint: fix the reference to point to a symbol that exists info: this error may be the result of a bug in Deno - if you think this is the case, please open an issue diff --git a/tests/specs/graph/fast_check/class_properties.txt b/tests/specs/graph/fast_check/class_properties.txt index 83812a8f3..500d7e0f2 100644 --- a/tests/specs/graph/fast_check/class_properties.txt +++ b/tests/specs/graph/fast_check/class_properties.txt @@ -106,8 +106,8 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: return {} as never; } } - const isSecure: Symbol = {} as never; - const public2: Symbol = {} as never; + declare const isSecure: Symbol; + declare const public2: Symbol; export class CookieMapBase { declare [isSecure]: boolean; [public2](): number { diff --git a/tests/specs/graph/fast_check/class_static_member_ref_not_found.txt b/tests/specs/graph/fast_check/class_static_member_ref_not_found.txt index 58fb2e315..608c31a2e 100644 --- a/tests/specs/graph/fast_check/class_static_member_ref_not_found.txt +++ b/tests/specs/graph/fast_check/class_static_member_ref_not_found.txt @@ -66,10 +66,13 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: | 4 | class Public1 { | ^^^^^^^^^^^^^^^ + | 5 | static prop: string; | ^^^^^^^^^^^^^^^^^^^^^^ + | 6 | } | ^ this is the reference + | = hint: fix the reference to point to a symbol that exists info: this error may be the result of a bug in Deno - if you think this is the case, please open an issue diff --git a/tests/specs/graph/fast_check/class_super_unsupported.txt b/tests/specs/graph/fast_check/class_super_unsupported.txt index bdb722ef1..d7bdaf31d 100644 --- a/tests/specs/graph/fast_check/class_super_unsupported.txt +++ b/tests/specs/graph/fast_check/class_super_unsupported.txt @@ -65,6 +65,7 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: | 4 | export class Child extends MyFunction(Base) { | ^^^^^^^^^^^^^^^^ this is the superclass expression + | = hint: extract the superclass expression into a variable info: fast check was unable to infer the type of the superclass expression diff --git a/tests/specs/graph/fast_check/comments.txt b/tests/specs/graph/fast_check/comments.txt index 4b94d8069..631acd923 100644 --- a/tests/specs/graph/fast_check/comments.txt +++ b/tests/specs/graph/fast_check/comments.txt @@ -61,7 +61,7 @@ import 'jsr:@scope/a' Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: {} // @ts-ignore broken line - export const value1: number = {} as never; + export declare const value1: number; --- DTS --- // @ts-ignore broken line export declare const value1: number; diff --git a/tests/specs/graph/fast_check/const_infer_function_missing_return.txt b/tests/specs/graph/fast_check/const_infer_function_missing_return.txt index 1fed5c4ff..22e07ea35 100644 --- a/tests/specs/graph/fast_check/const_infer_function_missing_return.txt +++ b/tests/specs/graph/fast_check/const_infer_function_missing_return.txt @@ -56,13 +56,7 @@ import 'jsr:@scope/a' } Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API - --> https://jsr.io/@scope/a/1.0.0/mod.ts:1:14 - | - 1 | export const test4 = function () { return "test" }; - | ^^^^^ this function is missing an explicit return type - = hint: add an explicit return type to the function - - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type - + {} + export declare const test4: () => string; + --- DTS --- + export declare const test4: () => string; diff --git a/tests/specs/graph/fast_check/cross_file_ref_module_not_found.txt b/tests/specs/graph/fast_check/cross_file_ref_module_not_found.txt index 47f7c0b06..0ac5779e9 100644 --- a/tests/specs/graph/fast_check/cross_file_ref_module_not_found.txt +++ b/tests/specs/graph/fast_check/cross_file_ref_module_not_found.txt @@ -142,12 +142,16 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: | 1 | export class A { | ^^^^^^^^^^^^^^^^ + | 2 | member: string; | ^^^^^^^^^^^^^^^^^ + | 3 | member2: string; | ^^^^^^^^^^^^^^^^^^ + | 4 | } | ^ this is the reference + | = hint: fix the reference to point to a symbol that exists info: this error may be the result of a bug in Deno - if you think this is the case, please open an issue diff --git a/tests/specs/graph/fast_check/default_export_expr_var.txt b/tests/specs/graph/fast_check/default_export_expr_var.txt index 160bd7b92..0af4cb024 100644 --- a/tests/specs/graph/fast_check/default_export_expr_var.txt +++ b/tests/specs/graph/fast_check/default_export_expr_var.txt @@ -67,7 +67,7 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: export interface $Type { prop: boolean; } - export const $: $Type = {} as never; + export declare const $: $Type; export default $; --- DTS --- export interface $Type { diff --git a/tests/specs/graph/fast_check/enums.txt b/tests/specs/graph/fast_check/enums.txt index e59258af7..3bbb91a96 100644 --- a/tests/specs/graph/fast_check/enums.txt +++ b/tests/specs/graph/fast_check/enums.txt @@ -108,7 +108,7 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: Value1 = "a", Value2 = "b" } - const value: number = {} as never; + declare const value = 10; export enum EnumWithNonConstInits { Value1 = new Public1().test, Value2 = new Public2().asdf * value + NonExportedEnum.Value @@ -120,7 +120,7 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: enum NonExportedEnum { Value } - const NUM: any = {} as never; + declare const NUM: any; export enum Foo1 { A = 1, B = "2", diff --git a/tests/specs/graph/fast_check/global_module.txt b/tests/specs/graph/fast_check/global_module.txt index 8220f4b12..6c6234097 100644 --- a/tests/specs/graph/fast_check/global_module.txt +++ b/tests/specs/graph/fast_check/global_module.txt @@ -63,8 +63,10 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: | 1 | global { | ^^^^^^^^ + | 2 | declare var Test: 5; | ^^^^^^^^^^^^^^^^^^^^^^ + | 3 | } | ^ = hint: remove the 'global' augmentation diff --git a/tests/specs/graph/fast_check/inference/basic.txt b/tests/specs/graph/fast_check/inference/basic.txt new file mode 100644 index 000000000..a0367fb4c --- /dev/null +++ b/tests/specs/graph/fast_check/inference/basic.txt @@ -0,0 +1,160 @@ +~~ {"workspaceFastCheck":true} ~~ +# workspace_members +[ + { + "base": "file:///", + "nv": "@scope/a@1.0.0", + "exports": { + ".": "./mod.ts" + } + } +] + +# mod.ts +export const str = "str"; +export let str2 = "str"; +export const num = 1; +export let num2 = 1; +export const bool = true; +export let bool2 = true; +export const regexp = /./; +export let regexp2 = /./; +export const bigint = 1n; +export let bigint2 = 1n; +export const symbol = Symbol(""); +export const symbol2 = Symbol.for(""); +export const symbol3 = Symbol(); +export let symbol4 = Symbol(""); +export let symbol5 = Symbol.for(""); +export let symbol6 = Symbol(); +export const tpl = `tpl`; +export let tpl2 = `tpl`; +export let tpl3 = `tpl ${globalThis}`; +export const nul = null; +export let nul2 = null; +export const undef = undefined; +export let undef2 = undefined; + +export const paren = (1); +export let paren2 = (1); + +export const satisfies = 1 satisfies number; +export let satisfies2 = 1 satisfies 1; + +export const sequence = (1, 2); + +let assign: string; +export const assign2 = assign = 1; + +export const assertion = globalThis as 2; +export const assertion2 = <2> globalThis; + +export const obj = { a: 1, 1: 2, "3": 3 }; +export const obj2 = { + get str() { return "" }, + set str(v: string) {}, + method(): string {} +}; + + +# output +{ + "roots": [ + "file:///mod.ts" + ], + "modules": [ + { + "kind": "esm", + "size": 1113, + "mediaType": "TypeScript", + "specifier": "file:///mod.ts" + } + ], + "redirects": {} +} + +Fast check file:///mod.ts: + {} + export declare const str = "str"; + export declare let str2: string; + export declare const num = 1; + export declare let num2: number; + export declare const bool = true; + export declare let bool2: boolean; + export declare const regexp: RegExp; + export declare let regexp2: RegExp; + export declare const bigint = 1n; + export declare let bigint2: bigint; + export declare const symbol: unique symbol; + export declare const symbol2: unique symbol; + export declare const symbol3: unique symbol; + export declare let symbol4: symbol; + export declare let symbol5: symbol; + export declare let symbol6: symbol; + export declare const tpl = "tpl"; + export declare let tpl2: string; + export declare let tpl3: string; + export declare const nul: null; + export declare let nul2: null; + export declare const undef: undefined; + export declare let undef2: undefined; + export declare const paren = 1; + export declare let paren2: number; + export declare const satisfies = 1; + export declare let satisfies2: number; + export declare const sequence = 2; + export declare const assign2 = 1; + export declare const assertion = 2; + export declare const assertion2 = 2; + export declare const obj: { + a: number; + 1: number; + "3": number; + }; + export declare const obj2: { + get str(): string; + set str(v: string); + method(): string; + }; + --- DTS --- + export declare const str: string; + export declare let str2: string; + export declare const num: number; + export declare let num2: number; + export declare const bool: boolean; + export declare let bool2: boolean; + export declare const regexp: RegExp; + export declare let regexp2: RegExp; + export declare const bigint: bigint; + export declare let bigint2: bigint; + export declare const symbol: unique symbol; + export declare const symbol2: unique symbol; + export declare const symbol3: unique symbol; + export declare let symbol4: symbol; + export declare let symbol5: symbol; + export declare let symbol6: symbol; + export declare const tpl: string; + export declare let tpl2: string; + export declare let tpl3: string; + export declare const nul: null; + export declare let nul2: null; + export declare const undef: undefined; + export declare let undef2: undefined; + export declare const paren: number; + export declare let paren2: number; + export declare const satisfies: number; + export declare let satisfies2: number; + export declare const sequence: number; + export declare const assign2: number; + export declare const assertion: number; + export declare const assertion2: number; + export declare const obj: { + a: number; + 1: number; + "3": number; + }; + export declare const obj2: { + get str(): string; + set str(v: string); + method(): string; + }; diff --git a/tests/specs/graph/fast_check/inference/const_assertion.txt b/tests/specs/graph/fast_check/inference/const_assertion.txt new file mode 100644 index 000000000..b18d18df4 --- /dev/null +++ b/tests/specs/graph/fast_check/inference/const_assertion.txt @@ -0,0 +1,87 @@ +~~ {"workspaceFastCheck":true} ~~ +# workspace_members +[ + { + "base": "file:///", + "nv": "@scope/a@1.0.0", + "exports": { + ".": "./mod.ts" + } + } +] + +# mod.ts +export let str = "Hello, world!" as const; +export let num = 42 as const; +export let bool = true as const; +export let bigint = 42n as const; + +export let paren = (1) as const; + +export let tuple = [1, 2] as const; +export let tuple2 = [1, [2, "str"]] as const; +export let tuple3 = [1, , 3] as const; + +export let obj = { a: 1, b: "str", c: [1] } as const; + +export let obj2 = { + get str() { return "" }, + set str(v: string) {}, + method(): string {} +} as const; + +# output +{ + "roots": [ + "file:///mod.ts" + ], + "modules": [ + { + "kind": "esm", + "size": 458, + "mediaType": "TypeScript", + "specifier": "file:///mod.ts" + } + ], + "redirects": {} +} + +Fast check file:///mod.ts: + {} + export declare let str: "Hello, world!"; + export declare let num: 42; + export declare let bool: true; + export declare let bigint: 42n; + export declare let paren: 1; + export declare let tuple: readonly [1, 2]; + export declare let tuple2: readonly [1, readonly [2, "str"]]; + export declare let tuple3: readonly [1, undefined, 3]; + export declare let obj: readonly { + readonly a: 1; + readonly b: "str"; + readonly c: readonly [1]; + }; + export declare let obj2: readonly { + get str(): string; + set str(v: string); + method(): string; + }; + --- DTS --- + export declare let str: "Hello, world!"; + export declare let num: 42; + export declare let bool: true; + export declare let bigint: 42n; + export declare let paren: 1; + export declare let tuple: readonly [1, 2]; + export declare let tuple2: readonly [1, readonly [2, "str"]]; + export declare let tuple3: readonly [1, undefined, 3]; + export declare let obj: readonly { + readonly a: 1; + readonly b: "str"; + readonly c: readonly [1]; + }; + export declare let obj2: readonly { + get str(): string; + set str(v: string); + method(): string; + }; diff --git a/tests/specs/graph/fast_check/inference/error.txt b/tests/specs/graph/fast_check/inference/error.txt new file mode 100644 index 000000000..d15332357 --- /dev/null +++ b/tests/specs/graph/fast_check/inference/error.txt @@ -0,0 +1,359 @@ +~~ {"workspaceFastCheck":true} ~~ +# workspace_members +[ + { + "base": "file:///", + "nv": "@scope/a@1.0.0", + "exports": { + ".": "./mod.ts" + } + } +] + +# mod.ts +export const tplExpr = `asd ${"asd"}`; + +export const arr = [1, 2, 3]; + +export const call = fetch(); + +export const objSpread = { ...{ a: 1 } }; +export const objShorthand = { globalThis }; + +export const tupleSpread = [1, ...[2, 3]] as const; + +export const fnExpr = function (a): void {}; +export const fnExpr2 = function () { return globalThis }; +export const fnExpr3 = function (a?: string, b: string): void { }; +export const fnExpr4 = function (a = "asd", b: string): void { }; + +export const arrowExpr = (a): void => {}; +export const arrowExpr2 = () => globalThis; +export const arrowExpr3 = (a?: string, b: string): void => { }; +export const arrowExpr4 = (a = "asd", b: string): void => { }; + +export const getter = { + get a() { + return globalThis; + } +}; +export const setter = { + set a(value) { + } +}; +export const method = { + a(): void { + return globalThis; + } +}; +export const method2 = { + a(val): void { + } +}; +export const method3 = { + a(val?: string, b: string): void { + } +}; +export const method4 = { + a(val = "asd", b: string): void { + } +}; + + +# output +{ + "roots": [ + "file:///mod.ts" + ], + "modules": [ + { + "kind": "esm", + "size": 1061, + "mediaType": "TypeScript", + "specifier": "file:///mod.ts" + } + ], + "redirects": {} +} + +Fast check file:///mod.ts: + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:1:14 + | + 1 | export const tplExpr = `asd ${"asd"}`; + | ^^^^^^^ this variable's type could not be inferred because its initializer + | ----- contains this expression in a template literal, which can not be inferred + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: expressions in template literals can not be inferred because the type of the resulting string can not be narrowed without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:3:14 + | + 3 | export const arr = [1, 2, 3]; + | ^^^ this variable's type could not be inferred because its initializer + | --------- contains this array literal, which can not be inferred unless marked 'as const' + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: array literals without 'as const' can not be inferred because the type of the array can not be narrowed without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:5:14 + | + 5 | export const call = fetch(); + | ^^^^ this variable's type could not be inferred because its initializer + | ------- contains this expression, of which the type could not be inferred + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:7:14 + | + 7 | export const objSpread = { ...{ a: 1 } }; + | ^^^^^^^^^ this variable's type could not be inferred because its initializer + | --- contains this spread property, which can not be inferred + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: spread properties can not be inferred because the type of the resulting object can not be narrowed without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:8:14 + | + 8 | export const objShorthand = { globalThis }; + | ^^^^^^^^^^^^ this variable's type could not be inferred because its initializer + | ---------- contains this shorthand property, which can not be inferred + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: shorthand properties can not be inferred because the type of the value referred to by the shorthand property is not known without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:10:14 + | + 10 | export const tupleSpread = [1, ...[2, 3]] as const; + | ^^^^^^^^^^^ this variable's type could not be inferred because its initializer + | --- contains this spread element, which can not be inferred + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: spread elements can not be inferred because the type of the resulting array can not be narrowed without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:12:14 + | + 12 | export const fnExpr = function (a): void {}; + | ^^^^^^ this variable's type could not be inferred because its initializer + | ------ contains this function expression + | - which has this parameter, the type of which could not be inferred from the default value + | + = hint: add an explicit type annotation to the function expression parameter in the variable declaration initializer + + info: all variables in the public API must have a known type + info: all parameters of a function expression must have an explicit type annotation or an inferrable default value + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:13:14 + | + 13 | export const fnExpr2 = function () { return globalThis }; + | ^^^^^^^ this variable's type could not be inferred because its initializer + | ------- contains this function expression, of which the return type could not be inferred + | ------ because the value returned here + | ---------- contains this expression, of which the type could not be inferred + | + = hint: add an explicit return type annotation to the function expression in the variable declaration initializer + + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:14:14 + | + 14 | export const fnExpr3 = function (a?: string, b: string): void { }; + | ^^^^^^^ this variable's type could not be inferred because its initializer + | ------- contains this function expression + | - which has this required parameter following an optional parameter or a parameter with a default value + | + = hint: make the function expression parameter in the variable declaration initializer optional or provide a default value + + info: all variables in the public API must have a known type + info: all required parameters of a function expression must precede optional parameters or parameters with default values + info: this is because to compute the type of a optional parameter that is followed by a required parameter, a type checker is needed + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:15:14 + | + 15 | export const fnExpr4 = function (a = "asd", b: string): void { }; + | ^^^^^^^ this variable's type could not be inferred because its initializer + | ------- contains this function expression + | - which has this required parameter following an optional parameter or a parameter with a default value + | + = hint: make the function expression parameter in the variable declaration initializer optional or provide a default value + + info: all variables in the public API must have a known type + info: all required parameters of a function expression must precede optional parameters or parameters with default values + info: this is because to compute the type of a optional parameter that is followed by a required parameter, a type checker is needed + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:17:14 + | + 17 | export const arrowExpr = (a): void => {}; + | ^^^^^^^^^ this variable's type could not be inferred because its initializer + | --------- contains this arrow expression + | - which has this parameter, the type of which could not be inferred from the default value + | + = hint: add an explicit type annotation to the arrow expression parameter in the variable declaration initializer + + info: all variables in the public API must have a known type + info: all parameters of an arrow expression must have an explicit type annotation or an inferrable default value + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:18:14 + | + 18 | export const arrowExpr2 = () => globalThis; + | ^^^^^^^^^^ this variable's type could not be inferred because its initializer + | ---------- contains this arrow expression, of which the return type could not be inferred from the returned value + | ---------- contains this expression, of which the type could not be inferred + | + = hint: add an explicit return type annotation to the arrow expression in the variable declaration initializer + + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:19:14 + | + 19 | export const arrowExpr3 = (a?: string, b: string): void => { }; + | ^^^^^^^^^^ this variable's type could not be inferred because its initializer + | ---------- contains this arrow expression + | --------- which has this required parameter following an optional parameter or a parameter with a default value + | + = hint: make the arrow expression parameter in the variable declaration initializer optional or provide a default value + + info: all variables in the public API must have a known type + info: all required parameters of an arrow expression must precede optional parameters or parameters with default values + info: this is because to compute the type of a optional parameter that is followed by a required parameter, a type checker is needed + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:20:14 + | + 20 | export const arrowExpr4 = (a = "asd", b: string): void => { }; + | ^^^^^^^^^^ this variable's type could not be inferred because its initializer + | ---------- contains this arrow expression + | --------- which has this required parameter following an optional parameter or a parameter with a default value + | + = hint: make the arrow expression parameter in the variable declaration initializer optional or provide a default value + + info: all variables in the public API must have a known type + info: all required parameters of an arrow expression must precede optional parameters or parameters with default values + info: this is because to compute the type of a optional parameter that is followed by a required parameter, a type checker is needed + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:22:14 + | + 22 | export const getter = { + | ^^^^^^ this variable's type could not be inferred because its initializer + | + 23 | get a() { + | - contains this object getter, of which the return type could not be inferred + | + 24 | return globalThis; + | ------ because the value returned here + | ---------- contains this expression, of which the type could not be inferred + | + = hint: add an explicit return type annotation to the object getter in the variable declaration initializer + + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:27:14 + | + 27 | export const setter = { + | ^^^^^^ this variable's type could not be inferred because its initializer + | + 28 | set a(value) { + | - contains this object setter + | ----- which has this parameter, the type of which could not be inferred from the default value + | + = hint: add an explicit type annotation to the object setter parameter in the variable declaration initializer + + info: all variables in the public API must have a known type + info: all parameters of an object setter must have an explicit type annotation or an inferrable default value + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:36:14 + | + 36 | export const method2 = { + | ^^^^^^^ this variable's type could not be inferred because its initializer + | + 37 | a(val): void { + | - contains this object method + | --- which has this parameter, the type of which could not be inferred from the default value + | + = hint: add an explicit type annotation to the object method parameter in the variable declaration initializer + + info: all variables in the public API must have a known type + info: all parameters of an object method must have an explicit type annotation or an inferrable default value + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:40:14 + | + 40 | export const method3 = { + | ^^^^^^^ this variable's type could not be inferred because its initializer + | + 41 | a(val?: string, b: string): void { + | - contains this object method + | - which has this required parameter following an optional parameter or a parameter with a default value + | + = hint: make the object method parameter in the variable declaration initializer optional or provide a default value + + info: all variables in the public API must have a known type + info: all required parameters of an object method must precede optional parameters or parameters with default values + info: this is because to compute the type of a optional parameter that is followed by a required parameter, a type checker is needed + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:44:14 + | + 44 | export const method4 = { + | ^^^^^^^ this variable's type could not be inferred because its initializer + | + 45 | a(val = "asd", b: string): void { + | - contains this object method + | - which has this required parameter following an optional parameter or a parameter with a default value + | + = hint: make the object method parameter in the variable declaration initializer optional or provide a default value + + info: all variables in the public API must have a known type + info: all required parameters of an object method must precede optional parameters or parameters with default values + info: this is because to compute the type of a optional parameter that is followed by a required parameter, a type checker is needed + docs: https://jsr.io/go/slow-type-unknown-var-type + diff --git a/tests/specs/graph/fast_check/inferred_unique_symbols.txt b/tests/specs/graph/fast_check/inferred_unique_symbols.txt index ea7fec7e2..3b7e254d4 100644 --- a/tests/specs/graph/fast_check/inferred_unique_symbols.txt +++ b/tests/specs/graph/fast_check/inferred_unique_symbols.txt @@ -63,8 +63,8 @@ import 'jsr:@scope/a' Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: {} - const key: unique symbol = {} as never; - const key2: unique symbol = {} as never; + declare const key: unique symbol; + declare const key2: unique symbol; export class MyClass { declare [key]: number; declare [key2]: string; diff --git a/tests/specs/graph/fast_check/inferred_unique_symbols__not_global.txt b/tests/specs/graph/fast_check/inferred_unique_symbols__not_global.txt index 852fdf536..8fb11cc7d 100644 --- a/tests/specs/graph/fast_check/inferred_unique_symbols__not_global.txt +++ b/tests/specs/graph/fast_check/inferred_unique_symbols__not_global.txt @@ -65,13 +65,16 @@ import 'jsr:@scope/a' } Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - error[missing-explicit-type]: missing explicit type in the public API + error[unknown-var-type]: unknown type for variable in the public API --> https://jsr.io/@scope/a/1.0.0/mod.ts:4:7 | 4 | const key = Symbol("#keys"); - | ^^^ this symbol is missing an explicit type - = hint: add an explicit type annotation to the symbol + | ^^^ this variable's type could not be inferred because its initializer + | --------------- contains this expression, of which the type could not be inferred + | + = hint: add an explicit type annotation to the variable declaration - info: all symbols in the public API must have an explicit type - docs: https://jsr.io/go/slow-type-missing-explicit-type + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type diff --git a/tests/specs/graph/fast_check/init_idents_and_members.txt b/tests/specs/graph/fast_check/init_idents_and_members.txt index 7e1cb06ef..423c998ce 100644 --- a/tests/specs/graph/fast_check/init_idents_and_members.txt +++ b/tests/specs/graph/fast_check/init_idents_and_members.txt @@ -19,7 +19,11 @@ namespace Test { export class B {} } -export const handlers = { +export const handlers: { + BaseHandler: typeof BaseHandler, + Private: typeof Public, + C: typeof Test.A, +} = { BaseHandler, Private: Public, C: Test.A, @@ -42,8 +46,8 @@ namespace Test { } export function test( - a = BaseHandler, - C = Test.A, + a: typeof BaseHandler = BaseHandler, + C: typeof Test.A = Test.A, ) { } @@ -99,13 +103,13 @@ import 'jsr:@scope/b' }, { "kind": "esm", - "size": 224, + "size": 310, "mediaType": "TypeScript", "specifier": "https://jsr.io/@scope/a/1.0.0/mod.ts" }, { "kind": "esm", - "size": 173, + "size": 208, "mediaType": "TypeScript", "specifier": "https://jsr.io/@scope/b/1.0.0/mod.ts" } @@ -130,10 +134,10 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: export class A { } } - export const handlers = { - BaseHandler, - Private: Public, - C: Test.A + export declare const handlers: { + BaseHandler: typeof BaseHandler; + Private: typeof Public; + C: typeof Test.A; }; --- DTS --- declare class BaseHandler { @@ -145,12 +149,11 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: } } export declare const handlers: { - readonly Private; - readonly C; + BaseHandler: typeof BaseHandler; + Private: typeof Public; + C: typeof Test.A; }; - --- DTS Diagnostics --- - unable to infer type from object property, skipping - at https://jsr.io/@scope/a/1.0.0/mod.ts@176 + Fast check https://jsr.io/@scope/b/1.0.0/mod.ts: {} class BaseHandler { @@ -159,7 +162,7 @@ Fast check https://jsr.io/@scope/b/1.0.0/mod.ts: export class A { } } - export function test(a = BaseHandler, C = Test.A): void {} + export function test(a?: typeof BaseHandler, C?: typeof Test.A): void {} --- DTS --- declare class BaseHandler { } @@ -167,9 +170,4 @@ Fast check https://jsr.io/@scope/b/1.0.0/mod.ts: export class A { } } - export declare function test(a?: any, C?: any): void; - --- DTS Diagnostics --- - unable to infer type, falling back to any type - at https://jsr.io/@scope/b/1.0.0/mod.ts@140 - unable to infer type, falling back to any type - at https://jsr.io/@scope/b/1.0.0/mod.ts@159 + export declare function test(a?: typeof BaseHandler, C?: typeof Test.A): void; diff --git a/tests/specs/graph/fast_check/issue_22544.txt b/tests/specs/graph/fast_check/issue_22544.txt index f30bc6c29..83d1de1b0 100644 --- a/tests/specs/graph/fast_check/issue_22544.txt +++ b/tests/specs/graph/fast_check/issue_22544.txt @@ -67,10 +67,10 @@ import 'jsr:@scope/a' Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: {} - const rawString1: Symbol = {} as never; - const rawString2: Symbol = {} as never; - const rawString3: Symbol = {} as never; - const rawString4: Symbol = {} as never; + declare const rawString1: Symbol; + declare const rawString2: Symbol; + declare const rawString3: Symbol; + declare const rawString4: Symbol; export interface RawString { [rawString1]: string; [rawString2](): void; diff --git a/tests/specs/graph/fast_check/issue_22829.txt b/tests/specs/graph/fast_check/issue_22829.txt index 6ec70be5b..5761bd45f 100644 --- a/tests/specs/graph/fast_check/issue_22829.txt +++ b/tests/specs/graph/fast_check/issue_22829.txt @@ -100,57 +100,19 @@ import 'jsr:@scope/a' } } -Fast check https://jsr.io/@scope/a/1.0.0/functions.ts: - {} - abstract class Internal { - declare prop: T; - } - function func(): void {} - export function other_func(): void {} - export const functions = { - func, - other: other_func - }; - export declare namespace functions { - type Function = Internal; - } - --- DTS --- - declare abstract class Internal { - prop: T; - } - declare function func(): void; - export declare function other_func(): void; - export declare const functions: { - readonly other; - }; - export declare namespace functions { - type Function = Internal; - } - --- DTS Diagnostics --- - unable to infer type from object property, skipping - at https://jsr.io/@scope/a/1.0.0/functions.ts@125 Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - { - "./functions.ts": { - "code": { - "specifier": "https://jsr.io/@scope/a/1.0.0/functions.ts", - "span": { - "start": { - "line": 0, - "character": 26 - }, - "end": { - "line": 0, - "character": 42 - } - } - } - } - } - import { functions } from "./functions.ts"; - export type Test = functions.Function; - export { functions } from "./functions.ts"; - --- DTS --- - import { functions } from "./functions.ts"; - export type Test = functions.Function; - export { functions } from "./functions.ts"; + error[unknown-var-type]: unknown type for variable in the public API + --> https://jsr.io/@scope/a/1.0.0/functions.ts:9:14 + | + 9 | export const functions = { + | ^^^^^^^^^ this variable's type could not be inferred because its initializer + | + 10 | func, + | ---- contains this shorthand property, which can not be inferred + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: shorthand properties can not be inferred because the type of the value referred to by the shorthand property is not known without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + diff --git a/tests/specs/graph/fast_check/issue_23658_1.txt b/tests/specs/graph/fast_check/issue_23658_1.txt index 486b94800..c5c535119 100644 --- a/tests/specs/graph/fast_check/issue_23658_1.txt +++ b/tests/specs/graph/fast_check/issue_23658_1.txt @@ -90,43 +90,17 @@ import 'jsr:@scope/a' } } -Fast check https://jsr.io/@scope/a/1.0.0/base.ts: - {} - export class Base { - } - --- DTS --- - export declare class Base { - } - Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - { - "./base.ts": { - "code": { - "specifier": "https://jsr.io/@scope/a/1.0.0/base.ts", - "span": { - "start": { - "line": 0, - "character": 30 - }, - "end": { - "line": 0, - "character": 41 - } - } - } - } - } - import * as adapter_base from "./base.ts"; - class ServerAdapter extends adapter_base.Base { - static adapt(): void {} - } - export const adapt = ServerAdapter.adapt; - --- DTS --- - import * as adapter_base from "./base.ts"; - declare class ServerAdapter extends adapter_base.Base { - static adapt(): void; - } - export declare const adapt: any; - --- DTS Diagnostics --- - unable to infer type, falling back to any type - at https://jsr.io/@scope/a/1.0.0/mod.ts@130 + error[unknown-var-type]: unknown type for variable in the public API + --> https://jsr.io/@scope/a/1.0.0/mod.ts:8:14 + | + 8 | export const adapt = ServerAdapter.adapt; + | ^^^^^ this variable's type could not be inferred because its initializer + | ------------------- contains this expression, of which the type could not be inferred + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + diff --git a/tests/specs/graph/fast_check/issue_23658_2.txt b/tests/specs/graph/fast_check/issue_23658_2.txt index 3222b7619..0e0454100 100644 --- a/tests/specs/graph/fast_check/issue_23658_2.txt +++ b/tests/specs/graph/fast_check/issue_23658_2.txt @@ -117,68 +117,17 @@ import 'jsr:@scope/a' } } -Fast check https://jsr.io/@scope/a/1.0.0/base.ts: - {} - export class Base { - } - --- DTS --- - export declare class Base { - } +Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: + error[unknown-var-type]: unknown type for variable in the public API + --> https://jsr.io/@scope/a/1.0.0/mod.ts:9:14 + | + 9 | export const adapt = ServerAdapter.adapt; + | ^^^^^ this variable's type could not be inferred because its initializer + | ------------------- contains this expression, of which the type could not be inferred + | + = hint: add an explicit type annotation to the variable declaration -Fast check https://jsr.io/@scope/a/1.0.0/interface.ts: - {} - export class IInterface { - } - --- DTS --- - export declare class IInterface { - } + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type -Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - { - "./base.ts": { - "code": { - "specifier": "https://jsr.io/@scope/a/1.0.0/base.ts", - "span": { - "start": { - "line": 0, - "character": 21 - }, - "end": { - "line": 0, - "character": 32 - } - } - } - }, - "./interface.ts": { - "type": { - "specifier": "https://jsr.io/@scope/a/1.0.0/interface.ts", - "span": { - "start": { - "line": 1, - "character": 32 - }, - "end": { - "line": 1, - "character": 48 - } - } - } - } - } - import { Base } from "./base.ts"; - import type { IInterface } from "./interface.ts"; - class ServerAdapter extends Base implements IInterface { - static adapt(): void {} - } - export const adapt = ServerAdapter.adapt; - --- DTS --- - import { Base } from "./base.ts"; - import type { IInterface } from "./interface.ts"; - declare class ServerAdapter extends Base implements IInterface { - static adapt(): void; - } - export declare const adapt: any; - --- DTS Diagnostics --- - unable to infer type, falling back to any type - at https://jsr.io/@scope/a/1.0.0/mod.ts@180 diff --git a/tests/specs/graph/fast_check/missing_return_type.txt b/tests/specs/graph/fast_check/missing_return_type.txt index cd31786bf..37b76a78e 100644 --- a/tests/specs/graph/fast_check/missing_return_type.txt +++ b/tests/specs/graph/fast_check/missing_return_type.txt @@ -58,13 +58,19 @@ import 'jsr:@scope/a' } Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> https://jsr.io/@scope/a/1.0.0/mod.ts:1:17 | 1 | export function missingReturnType() { - | ^^^^^^^^^^^^^^^^^ this function is missing an explicit return type + | ----------------- this function's return type could not be inferred + | + 2 | return Math.random(); + | ------ because the value returned here + | ------------- contains this expression, of which the type could not be inferred + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type diff --git a/tests/specs/graph/fast_check/missing_return_type_generator.txt b/tests/specs/graph/fast_check/missing_return_type_generator.txt index 4373df47e..68ecd9156 100644 --- a/tests/specs/graph/fast_check/missing_return_type_generator.txt +++ b/tests/specs/graph/fast_check/missing_return_type_generator.txt @@ -57,13 +57,15 @@ import 'jsr:@scope/a' } Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> https://jsr.io/@scope/a/1.0.0/mod.ts:1:18 | 1 | export function* missingReturnType() { - | ^^^^^^^^^^^^^^^^^ this function is missing an explicit return type + | ----------------- this function is missing an explicit return type annotation + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: a function declaration that is a generator must have an explicit return type annotation because the return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type diff --git a/tests/specs/graph/fast_check/ref_obj_type.txt b/tests/specs/graph/fast_check/ref_obj_type.txt index 1557cc598..f05cde9f0 100644 --- a/tests/specs/graph/fast_check/ref_obj_type.txt +++ b/tests/specs/graph/fast_check/ref_obj_type.txt @@ -68,18 +68,18 @@ import 'jsr:@scope/a' Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: {} - export const STATUS_CODE = { - /** RFC 7231, 6.2.1 */ Continue: 100, - /** RFC 7231, 6.2.2 */ SwitchingProtocols: 101, - /** RFC 2518, 10.1 */ Processing: 102, - /** RFC 8297 **/ EarlyHints: 103 + export declare const STATUS_CODE: { + /** RFC 7231, 6.2.1 */ Continue: number; + /** RFC 7231, 6.2.2 */ SwitchingProtocols: number; + /** RFC 2518, 10.1 */ Processing: number; + /** RFC 8297 **/ EarlyHints: number; }; export type Status = typeof STATUS_CODE.Continue; --- DTS --- export declare const STATUS_CODE: { - readonly /** RFC 7231, 6.2.1 */ Continue: number; - readonly /** RFC 7231, 6.2.2 */ SwitchingProtocols: number; - readonly /** RFC 2518, 10.1 */ Processing: number; - readonly /** RFC 8297 **/ EarlyHints: number; + /** RFC 7231, 6.2.1 */ Continue: number; + /** RFC 7231, 6.2.2 */ SwitchingProtocols: number; + /** RFC 2518, 10.1 */ Processing: number; + /** RFC 8297 **/ EarlyHints: number; }; export type Status = typeof STATUS_CODE.Continue; diff --git a/tests/specs/graph/fast_check/ref_var_no_type.txt b/tests/specs/graph/fast_check/ref_var_no_type.txt index 151189b42..e87f3896b 100644 --- a/tests/specs/graph/fast_check/ref_var_no_type.txt +++ b/tests/specs/graph/fast_check/ref_var_no_type.txt @@ -62,14 +62,14 @@ import 'jsr:@scope/a' Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: {} - export const symbols = { - writable: function(): void {}, - readable: 1234 + export declare const symbols: { + writable: () => void; + readable: number; }; export type Status = typeof symbols.writable; --- DTS --- export declare const symbols: { - readonly writable: () => void; - readonly readable: number; + writable: () => void; + readable: number; }; export type Status = typeof symbols.writable; diff --git a/tests/specs/graph/fast_check/ref_var_type.txt b/tests/specs/graph/fast_check/ref_var_type.txt index 172438fe9..4dd64992e 100644 --- a/tests/specs/graph/fast_check/ref_var_type.txt +++ b/tests/specs/graph/fast_check/ref_var_type.txt @@ -67,7 +67,7 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: interface Symbols { readable: unique symbol; } - export const symbols: Symbols = {} as never; + export declare const symbols: Symbols; export type Status = typeof symbols.readable; --- DTS --- interface Symbols { diff --git a/tests/specs/graph/fast_check/return_inference/empty.txt b/tests/specs/graph/fast_check/return_inference/empty.txt index f1d0b803e..a5adf7afd 100644 --- a/tests/specs/graph/fast_check/return_inference/empty.txt +++ b/tests/specs/graph/fast_check/return_inference/empty.txt @@ -25,11 +25,10 @@ export class D { } } -// TODO: these are not yet handled -// export const e = { -// e() { -// } -// }; +export const e = { + e() { + } +}; // TODO: these are not yet handled // export const f = class { @@ -46,7 +45,7 @@ export class D { "modules": [ { "kind": "esm", - "size": 288, + "size": 241, "mediaType": "TypeScript", "specifier": "file:///mod.ts" } @@ -56,12 +55,15 @@ export class D { Fast check file:///mod.ts: {} - export const a = (): void =>{}; - export const b = function(): void {}; + export declare const a: () => void; + export declare const b: () => void; export function c(): void {} export class D { d(): void {} } + export declare const e: { + e(): void; + }; --- DTS --- export declare const a: () => void; export declare const b: () => void; @@ -69,3 +71,6 @@ Fast check file:///mod.ts: export declare class D { d(): void; } + export declare const e: { + e(): void; + }; diff --git a/tests/specs/graph/fast_check/return_inference/generator_err.txt b/tests/specs/graph/fast_check/return_inference/generator_err.txt new file mode 100644 index 000000000..9ab2178da --- /dev/null +++ b/tests/specs/graph/fast_check/return_inference/generator_err.txt @@ -0,0 +1,102 @@ +~~ {"workspaceFastCheck":true} ~~ +# workspace_members +[ + { + "base": "file:///", + "nv": "@scope/a@1.0.0", + "exports": { + ".": "./mod.ts" + } + } +] + +# mod.ts +// Arrow functions can not be generator functions + +export const b = function*() { +} + +export function* c() { +} + +export class D { + *d() { + } +} + +export const e = { + *e() { + } +}; + + + +# output +{ + "roots": [ + "file:///mod.ts" + ], + "modules": [ + { + "kind": "esm", + "size": 181, + "mediaType": "TypeScript", + "specifier": "file:///mod.ts" + } + ], + "redirects": {} +} + +Fast check file:///mod.ts: + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:3:14 + | + 3 | export const b = function*() { + | ^ this variable's type could not be inferred because its initializer + | - contains this function expression, which is missing an explicit return type annotation + | + = hint: add an explicit return type annotation to the function expression in the variable declaration initializer + + info: all variables in the public API must have a known type + info: a function expression that is a generator must have an explicit return type annotation because the return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-return-type]: unknown return type for function in the public API + --> /mod.ts:6:18 + | + 6 | export function* c() { + | - this function is missing an explicit return type annotation + | + = hint: add an explicit return type to the function + + info: all functions in the public API must have an known return type + info: a function declaration that is a generator must have an explicit return type annotation because the return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type + + error[unknown-return-type]: unknown return type for function in the public API + --> /mod.ts:10:4 + | + 10 | *d() { + | - this function is missing an explicit return type annotation + | + = hint: add an explicit return type to the function + + info: all functions in the public API must have an known return type + info: a function declaration that is a generator must have an explicit return type annotation because the return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:14:14 + | + 14 | export const e = { + | ^ this variable's type could not be inferred because its initializer + | + 15 | *e() { + | - contains this object method, which is missing an explicit return type annotation + | + = hint: add an explicit return type annotation to the object method in the variable declaration initializer + + info: all variables in the public API must have a known type + info: an object method that is a generator must have an explicit return type annotation because the return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + diff --git a/tests/specs/graph/fast_check/return_inference/multiple_value_return_err.txt b/tests/specs/graph/fast_check/return_inference/multiple_value_return_err.txt index fa29c8b10..6e48ad05f 100644 --- a/tests/specs/graph/fast_check/return_inference/multiple_value_return_err.txt +++ b/tests/specs/graph/fast_check/return_inference/multiple_value_return_err.txt @@ -33,13 +33,12 @@ export class D { } } -// TODO: we don't support this at all -// export const e = { -// e() { -// if (globalThis) return 1; -// return 2; -// } -// }; +export const e = { + e() { + if (globalThis) return 1; + return 2; + } +}; // TODO: we don't support this at all // export const f = class { @@ -57,7 +56,7 @@ export class D { "modules": [ { "kind": "esm", - "size": 557, + "size": 501, "mediaType": "TypeScript", "specifier": "file:///mod.ts" } @@ -66,43 +65,68 @@ export class D { } Fast check file:///mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-var-type]: unknown type for variable in the public API --> /mod.ts:1:14 | 1 | export const a = () => { - | ^ this function is missing an explicit return type - = hint: add an explicit return type to the function + | ^ this variable's type could not be inferred because its initializer + | - contains this arrow expression, which is missing an explicit return type annotation + | + = hint: add an explicit return type annotation to the arrow expression in the variable declaration initializer - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all variables in the public API must have a known type + info: an arrow expression has multiple return statements with values, so a return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-var-type]: unknown type for variable in the public API --> /mod.ts:6:14 | 6 | export const b = function() { - | ^ this function is missing an explicit return type - = hint: add an explicit return type to the function + | ^ this variable's type could not be inferred because its initializer + | - contains this function expression, which is missing an explicit return type annotation + | + = hint: add an explicit return type annotation to the function expression in the variable declaration initializer - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all variables in the public API must have a known type + info: a function expression has multiple return statements with values, so a return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> /mod.ts:11:17 | 11 | export function c() { - | ^ this function is missing an explicit return type + | - this function is missing an explicit return type annotation + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: a function declaration has multiple return statements with values, so a return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> /mod.ts:17:3 | 17 | d() { - | ^ this function is missing an explicit return type + | - this function is missing an explicit return type annotation + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: a function declaration has multiple return statements with values, so a return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:23:14 + | + 23 | export const e = { + | ^ this variable's type could not be inferred because its initializer + | + 24 | e() { + | - contains this object method, which is missing an explicit return type annotation + | + = hint: add an explicit return type annotation to the object method in the variable declaration initializer + + info: all variables in the public API must have a known type + info: an object method has multiple return statements with values, so a return type can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type diff --git a/tests/specs/graph/fast_check/return_inference/multiple_void_return.txt b/tests/specs/graph/fast_check/return_inference/multiple_void_return.txt index 9f040e1a2..aa1d69634 100644 --- a/tests/specs/graph/fast_check/return_inference/multiple_void_return.txt +++ b/tests/specs/graph/fast_check/return_inference/multiple_void_return.txt @@ -33,13 +33,12 @@ export class D { } } -// TODO: these are not yet handled -// export const e = { -// e() { -// if (globalThis) return; -// return; -// } -// }; +export const e = { + e() { + if (globalThis) return; + return; + } +}; // TODO: these are not yet handled // export const f = class { @@ -58,7 +57,7 @@ export class D { "modules": [ { "kind": "esm", - "size": 528, + "size": 475, "mediaType": "TypeScript", "specifier": "file:///mod.ts" } @@ -68,12 +67,15 @@ export class D { Fast check file:///mod.ts: {} - export const a = (): void =>{}; - export const b = function(): void {}; + export declare const a: () => void; + export declare const b: () => void; export function c(): void {} export class D { d(): void {} } + export declare const e: { + e(): void; + }; --- DTS --- export declare const a: () => void; export declare const b: () => void; @@ -81,3 +83,6 @@ Fast check file:///mod.ts: export declare class D { d(): void; } + export declare const e: { + e(): void; + }; diff --git a/tests/specs/graph/fast_check/return_inference/no_return.txt b/tests/specs/graph/fast_check/return_inference/no_return.txt index 6cdde238f..a5285df7e 100644 --- a/tests/specs/graph/fast_check/return_inference/no_return.txt +++ b/tests/specs/graph/fast_check/return_inference/no_return.txt @@ -23,7 +23,6 @@ export class D { } } - # output { "roots": [ @@ -32,7 +31,7 @@ export class D { "modules": [ { "kind": "esm", - "size": 112, + "size": 111, "mediaType": "TypeScript", "specifier": "file:///mod.ts" } diff --git a/tests/specs/graph/fast_check/return_inference/no_return_err.txt b/tests/specs/graph/fast_check/return_inference/no_return_err.txt index 4e3ddae38..6eeebaa78 100644 --- a/tests/specs/graph/fast_check/return_inference/no_return_err.txt +++ b/tests/specs/graph/fast_check/return_inference/no_return_err.txt @@ -25,12 +25,11 @@ export const b = function() { // This can be inferred for class declarations. -// TODO: we don't support this at all -// export const e = { -// e() { -// exit(); -// } -// }; +export const e = { + e() { + exit(); + } +}; // TODO: we don't support this at all // export const f = class { @@ -48,7 +47,7 @@ export const b = function() { "modules": [ { "kind": "esm", - "size": 421, + "size": 368, "mediaType": "TypeScript", "specifier": "file:///mod.ts" } @@ -57,27 +56,47 @@ export const b = function() { } Fast check file:///mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-var-type]: unknown type for variable in the public API --> /mod.ts:3:14 | 3 | export const a = () => { - | ^ this function is missing an explicit return type - = hint: add an explicit return type of 'void' or 'never' to the function + | ^ this variable's type could not be inferred because its initializer + | - contains this arrow expression, which is missing an explicit return type annotation + | + = hint: add an explicit return type annotation to the arrow expression in the variable declaration initializer - info: all functions in the public API must have an explicit return type - info: function expressions without a return statement can have a return type of either 'void' or 'never' - info: this function has no return statements, so a return type could not be inferred automatically - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all variables in the public API must have a known type + info: the return type of an arrow expression can not be inferred if it has no return statements + info: this is because an arrow expressions without a return statement can either return 'void' or 'never', and the specific type can not be determined without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-var-type]: unknown type for variable in the public API --> /mod.ts:7:14 | 7 | export const b = function() { - | ^ this function is missing an explicit return type - = hint: add an explicit return type of 'void' or 'never' to the function + | ^ this variable's type could not be inferred because its initializer + | - contains this function expression, which is missing an explicit return type annotation + | + = hint: add an explicit return type annotation to the function expression in the variable declaration initializer + + info: all variables in the public API must have a known type + info: the return type of a function expression can not be inferred if it has no return statements + info: this is because a function expressions without a return statement can either return 'void' or 'never', and the specific type can not be determined without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:15:14 + | + 15 | export const e = { + | ^ this variable's type could not be inferred because its initializer + | + 16 | e() { + | - contains this object method, which is missing an explicit return type annotation + | + = hint: add an explicit return type annotation to the object method in the variable declaration initializer - info: all functions in the public API must have an explicit return type - info: function expressions without a return statement can have a return type of either 'void' or 'never' - info: this function has no return statements, so a return type could not be inferred automatically - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all variables in the public API must have a known type + info: the return type of an object method can not be inferred if it has no return statements + info: this is because an object methods without a return statement can either return 'void' or 'never', and the specific type can not be determined without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type diff --git a/tests/specs/graph/fast_check/return_inference/value_return.txt b/tests/specs/graph/fast_check/return_inference/value_return.txt new file mode 100644 index 000000000..52c7e4e54 --- /dev/null +++ b/tests/specs/graph/fast_check/return_inference/value_return.txt @@ -0,0 +1,85 @@ +~~ {"workspaceFastCheck":true} ~~ +# workspace_members +[ + { + "base": "file:///", + "nv": "@scope/a@1.0.0", + "exports": { + ".": "./mod.ts" + } + } +] + +# mod.ts +export const a = () => { + return 2; +} + +export const b = function() { + return 2; +} + +export function c() { + return 2; +} + +export class D { + d() { + return 2; + } +} + +export const e = { + e() { + return 2; + } +}; + +// TODO: we don't support this at all +// export const f = class { +// f() { +// return 2; +// } +// }; + +# output +{ + "roots": [ + "file:///mod.ts" + ], + "modules": [ + { + "kind": "esm", + "size": 324, + "mediaType": "TypeScript", + "specifier": "file:///mod.ts" + } + ], + "redirects": {} +} + +Fast check file:///mod.ts: + {} + export declare const a: () => number; + export declare const b: () => number; + export function c(): number { + return {} as never; + } + export class D { + d(): number { + return {} as never; + } + } + export declare const e: { + e(): number; + }; + --- DTS --- + export declare const a: () => number; + export declare const b: () => number; + export declare function c(): number; + export declare class D { + d(): number; + } + export declare const e: { + e(): number; + }; diff --git a/tests/specs/graph/fast_check/return_inference/value_return_err.txt b/tests/specs/graph/fast_check/return_inference/value_return_err.txt index 095e1d54d..e60e448cb 100644 --- a/tests/specs/graph/fast_check/return_inference/value_return_err.txt +++ b/tests/specs/graph/fast_check/return_inference/value_return_err.txt @@ -12,29 +12,28 @@ # mod.ts export const a = () => { - return 2; + return a; } export const b = function() { - return 2; + return b; } export function c() { - return 2; + return c; } export class D { d() { - return 2; + return D; } } -// TODO: we don't support this at all -// export const e = { -// e() { -// return 2; -// } -// }; +export const e = { + e() { + return e; + } +}; // TODO: we don't support this at all // export const f = class { @@ -51,7 +50,7 @@ export class D { "modules": [ { "kind": "esm", - "size": 377, + "size": 324, "mediaType": "TypeScript", "specifier": "file:///mod.ts" } @@ -60,43 +59,88 @@ export class D { } Fast check file:///mod.ts: - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-var-type]: unknown type for variable in the public API --> /mod.ts:1:14 | 1 | export const a = () => { - | ^ this function is missing an explicit return type - = hint: add an explicit return type to the function + | ^ this variable's type could not be inferred because its initializer + | - contains this arrow expression, of which the return type could not be inferred + | + 2 | return a; + | ------ because the value returned here + | - contains this expression, of which the type could not be inferred + | + = hint: add an explicit return type annotation to the arrow expression in the variable declaration initializer - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-var-type]: unknown type for variable in the public API --> /mod.ts:5:14 | 5 | export const b = function() { - | ^ this function is missing an explicit return type - = hint: add an explicit return type to the function + | ^ this variable's type could not be inferred because its initializer + | - contains this function expression, of which the return type could not be inferred + | + 6 | return b; + | ------ because the value returned here + | - contains this expression, of which the type could not be inferred + | + = hint: add an explicit return type annotation to the function expression in the variable declaration initializer - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type - error[missing-explicit-return-type]: missing explicit return type in the public API - --> /mod.ts:9:17 - | - 9 | export function c() { - | ^ this function is missing an explicit return type - = hint: add an explicit return type to the function + error[unknown-return-type]: unknown return type for function in the public API + --> /mod.ts:9:17 + | + 9 | export function c() { + | - this function's return type could not be inferred + | + 10 | return c; + | ------ because the value returned here + | - contains this expression, of which the type could not be inferred + | + = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type - error[missing-explicit-return-type]: missing explicit return type in the public API + error[unknown-return-type]: unknown return type for function in the public API --> /mod.ts:14:3 | 14 | d() { - | ^ this function is missing an explicit return type + | - this function's return type could not be inferred + | + 15 | return D; + | ------ because the value returned here + | - contains this expression, of which the type could not be inferred + | = hint: add an explicit return type to the function - info: all functions in the public API must have an explicit return type - docs: https://jsr.io/go/slow-type-missing-explicit-return-type + info: all functions in the public API must have an known return type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-return-type + + error[unknown-var-type]: unknown type for variable in the public API + --> /mod.ts:19:14 + | + 19 | export const e = { + | ^ this variable's type could not be inferred because its initializer + | + 20 | e() { + | - contains this object method, of which the return type could not be inferred + | + 21 | return e; + | ------ because the value returned here + | - contains this expression, of which the type could not be inferred + | + = hint: add an explicit return type annotation to the object method in the variable declaration initializer + + info: all variables in the public API must have a known type + info: the type of arbitrary expressions can not be inferred without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type diff --git a/tests/specs/graph/fast_check/return_inference/void_return.txt b/tests/specs/graph/fast_check/return_inference/void_return.txt index fcd21b032..d6703a3d1 100644 --- a/tests/specs/graph/fast_check/return_inference/void_return.txt +++ b/tests/specs/graph/fast_check/return_inference/void_return.txt @@ -29,12 +29,11 @@ export class D { } } -// TODO: these are not yet handled -// export const e = { -// e() { -// return; -// } -// }; +export const e = { + e() { + return; + } +}; // TODO: these are not yet handled // export const f = class { @@ -52,7 +51,7 @@ export class D { "modules": [ { "kind": "esm", - "size": 360, + "size": 310, "mediaType": "TypeScript", "specifier": "file:///mod.ts" } @@ -62,12 +61,15 @@ export class D { Fast check file:///mod.ts: {} - export const a = (): void =>{}; - export const b = function(): void {}; + export declare const a: () => void; + export declare const b: () => void; export function c(): void {} export class D { d(): void {} } + export declare const e: { + e(): void; + }; --- DTS --- export declare const a: () => void; export declare const b: () => void; @@ -75,3 +77,6 @@ Fast check file:///mod.ts: export declare class D { d(): void; } + export declare const e: { + e(): void; + }; diff --git a/tests/specs/graph/fast_check/test_test_test.txt b/tests/specs/graph/fast_check/test_test_test.txt new file mode 100644 index 000000000..ba6d4d6e2 --- /dev/null +++ b/tests/specs/graph/fast_check/test_test_test.txt @@ -0,0 +1,47 @@ +~~ {"workspaceFastCheck":true} ~~ +# workspace_members +[ + { + "base": "file:///", + "nv": "@scope/a@1.0.0", + "exports": { + ".": "./mod.ts" + } + } +] + +# mod.ts +// export function a() { +// var x = ""; +// return {} as typeof x; +// }; + +# output +{ + "roots": [ + "file:///mod.ts" + ], + "modules": [ + { + "kind": "esm", + "size": 179, + "mediaType": "TypeScript", + "specifier": "file:///mod.ts" + } + ], + "redirects": {} +} + +Fast check file:///mod.ts: + {} + declare const Y: X; + interface X { + y: string; + } + export declare const a: (b: string, c?: typeof Y.z) => void; + --- DTS --- + declare const Y: X; + interface X { + y: string; + } + export declare const a: (b: string, c?: typeof Y.z) => void; diff --git a/tests/specs/graph/fast_check/ts_as_const.txt b/tests/specs/graph/fast_check/ts_as_const.txt index c818b8a78..6b9bcb980 100644 --- a/tests/specs/graph/fast_check/ts_as_const.txt +++ b/tests/specs/graph/fast_check/ts_as_const.txt @@ -69,40 +69,18 @@ import 'jsr:@scope/a' } Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - {} - export const foo = [ - 1, - 2 - ] as const; - export const bar = [ - 1, - , - 2 - ] as const; - export const obj = { - str: "bar", - bool: true, - bool2: false, - num: 42, - nullish: null - } as const; - export const spread = { - foo: 1, - ...obj - } as const; - --- DTS --- - export declare const foo: readonly [1, 2]; - export declare const bar: readonly [1, any, 2]; - export declare const obj: { - readonly str: "bar"; - readonly bool: true; - readonly bool2: false; - readonly num: 42; - readonly nullish: null; - }; - export declare const spread: { - readonly foo: 1; - }; - --- DTS Diagnostics --- - unable to infer type from spread, skipping - at https://jsr.io/@scope/a/1.0.0/mod.ts@215 + error[unknown-var-type]: unknown type for variable in the public API + --> https://jsr.io/@scope/a/1.0.0/mod.ts:11:14 + | + 11 | export const spread = { + | ^^^^^^ this variable's type could not be inferred because its initializer + | + 13 | ...obj, + | --- contains this spread property, which can not be inferred + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: spread properties can not be inferred because the type of the resulting object can not be narrowed without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + diff --git a/tests/specs/graph/fast_check/ts_const_assertion.txt b/tests/specs/graph/fast_check/ts_const_assertion.txt index c2a592589..2088c08b9 100644 --- a/tests/specs/graph/fast_check/ts_const_assertion.txt +++ b/tests/specs/graph/fast_check/ts_const_assertion.txt @@ -62,25 +62,22 @@ import 'jsr:@scope/a' Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: {} - export const a = "foo" as const; - export const b = 2 as const; - export const c = true as const; - export const d = false as const; - export const g = [ - 1, - 2 - ] as const; - export const h = { - a: 1, - b: 2 - } as const; + export declare const a = "foo"; + export declare const b = 2; + export declare const c = true; + export declare const d = false; + export declare const g: readonly [1, 2]; + export declare const h: readonly { + readonly a: 1; + readonly b: 2; + }; --- DTS --- - export declare const a: "foo"; - export declare const b: 2; - export declare const c: true; - export declare const d: false; + export declare const a: string; + export declare const b: number; + export declare const c: boolean; + export declare const d: boolean; export declare const g: readonly [1, 2]; - export declare const h: { + export declare const h: readonly { readonly a: 1; readonly b: 2; }; diff --git a/tests/specs/graph/fast_check/type_assertion.txt b/tests/specs/graph/fast_check/type_assertion.txt index 2b26b0dbb..347786c13 100644 --- a/tests/specs/graph/fast_check/type_assertion.txt +++ b/tests/specs/graph/fast_check/type_assertion.txt @@ -94,9 +94,9 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: export class Application { declare prop: S; } - export const str: "foo" & { + export declare const str: "foo" & { __brand: "foo"; - } = {} as never; + }; export function createMockApp = Record>(state?: S): Application { return {} as never; } @@ -106,7 +106,7 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: declare handler: Public2; declare secondProp: Public4; } - export const var1: Public5 = {} as never; + export declare const var1: Public5; interface Public1 { } interface Public2 { @@ -121,9 +121,9 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: } class Public7 { } - export const str2: "foo" & { + export declare const str2: "foo" & { data: Public7; - } = {} as never; + }; --- DTS --- export declare class Application { prop: S; diff --git a/tests/specs/graph/fast_check/unsupported_default_export_expr.txt b/tests/specs/graph/fast_check/unsupported_default_export_expr.txt index ff104fe91..1f8e744d4 100644 --- a/tests/specs/graph/fast_check/unsupported_default_export_expr.txt +++ b/tests/specs/graph/fast_check/unsupported_default_export_expr.txt @@ -65,8 +65,10 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: | 3 | export default { | ^^^^^^^^^^^^^^^^ + | 4 | test: new Class(), | ^^^^^^^^^^^^^^^^^^^^ + | 5 | }; | ^^ = hint: add an 'as' clause with an explicit type after the expression, or extract to a variable diff --git a/tests/specs/graph/fast_check/unsupported_private_member_ref.txt b/tests/specs/graph/fast_check/unsupported_private_member_ref.txt index 91a090372..992e88cd1 100644 --- a/tests/specs/graph/fast_check/unsupported_private_member_ref.txt +++ b/tests/specs/graph/fast_check/unsupported_private_member_ref.txt @@ -64,6 +64,7 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: | 3 | private myPrivateMember!: string; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is the reference + | = hint: extract the type of the private member to a type alias and reference the type alias instead info: private members can not be referenced from public API members diff --git a/tests/specs/graph/fast_check/var_arrow_leavable.txt b/tests/specs/graph/fast_check/var_arrow_leavable.txt index 63a452a90..35340d297 100644 --- a/tests/specs/graph/fast_check/var_arrow_leavable.txt +++ b/tests/specs/graph/fast_check/var_arrow_leavable.txt @@ -115,8 +115,8 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: } } import type { Foo, Bar } from "./b.ts"; - export const foo = (foo: Foo): string =>({} as never); - export const bar = (): Bar =>({} as never); + export declare const foo: (foo: Foo) => string; + export declare const bar: () => Bar; --- DTS --- import type { Foo, Bar } from "./b.ts"; export declare const foo: (foo: Foo) => string; diff --git a/tests/specs/graph/fast_check/var_function_leavable.txt b/tests/specs/graph/fast_check/var_function_leavable.txt index 894462395..96131afcd 100644 --- a/tests/specs/graph/fast_check/var_function_leavable.txt +++ b/tests/specs/graph/fast_check/var_function_leavable.txt @@ -115,12 +115,8 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: } } import type { Foo, Bar } from "./b.ts"; - export const foo = function(foo: Foo): string { - return {} as never; - }; - export const bar = function(): Bar { - return {} as never; - }; + export declare const foo: (foo: Foo) => string; + export declare const bar: () => Bar; --- DTS --- import type { Foo, Bar } from "./b.ts"; export declare const foo: (foo: Foo) => string; diff --git a/tests/specs/graph/fast_check/vars.txt b/tests/specs/graph/fast_check/vars.txt index 967a85f6f..bc06f5db2 100644 --- a/tests/specs/graph/fast_check/vars.txt +++ b/tests/specs/graph/fast_check/vars.txt @@ -108,109 +108,16 @@ import 'jsr:@scope/a' } Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: - {} - const public1: Public1 = {} as never; - export { public1 }; - class Public1 { - } - const ERROR_STATUS_MAP = { - "BadRequest": 400, - "Unauthorized": 401, - "PaymentRequired": 402, - "Forbidden": 403 - } as const; - export type ErrorStatusKeys = keyof typeof ERROR_STATUS_MAP; - export const asIs1 = [ - 1, - 2, - 3 - ]; - export const asIs2 = { - a: [ - 1, - 2, - 3 - ], - b: true, - c: 10, - d: 10n, - e: 1 * 2, - [1]: 4, - f: 1 ? true : false, - g: 1++, - h: [ - ...[ - 1, - 2 - ], - ...[ - "test" - ] - ] - }; - export const func1 = function(): string { - return {} as never; - }; - export const func2 = (): string =>({} as never); - export const func3 = (): string =>({} as never); - export const func4 = ()=>"test" as const; - export const func5 = (): Promise =>({} as never); - export const func6 = (): Promise<1> =>({} as never); - export const func7 = (): Promise<1> =>({} as never); - export const func8 = async ()=>"test" as const; - export const inferred1: 1 = {} as never; - export const inferred2: string = {} as never; - export const inferred3: true = {} as never; - export const inferred4: RegExp = {} as never; - export const inferred5: boolean = {} as never; - export const inferred6: boolean = {} as never; - export const inferred7: 1 | 2 | 3 & 4 = {} as never; - export const inferred8: ["test", 1] = {} as never; - export const inferred9: [...string] = {} as never; - export const inferred10: (1 | 2n)[] = {} as never; - export const inferred11: (keyof string)[] = {} as never; - export const inferred12: number = {} as never; - --- DTS --- - declare const public1: Public1; - export { public1 }; - declare class Public1 { - } - declare const ERROR_STATUS_MAP: { - readonly "BadRequest": 400; - readonly "Unauthorized": 401; - readonly "PaymentRequired": 402; - readonly "Forbidden": 403; - }; - export type ErrorStatusKeys = keyof typeof ERROR_STATUS_MAP; - export declare const asIs1: readonly [number, number, number]; - export declare const asIs2: { - readonly a: readonly [number, number, number]; - readonly b: boolean; - readonly c: number; - readonly d: bigint; - readonly e; - readonly [1]: number; - readonly f; - readonly g; - readonly h: readonly [readonly [number, number], readonly [string]]; - }; - export declare const func1: () => string; - export declare const func2: () => string; - export declare const func3: () => string; - export declare const func4: () => any; - export declare const func5: () => Promise; - export declare const func6: () => Promise<1>; - export declare const func7: () => Promise<1>; - export declare const func8: () => any; - export declare const inferred1: 1; - export declare const inferred2: string; - export declare const inferred3: true; - export declare const inferred4: RegExp; - export declare const inferred5: boolean; - export declare const inferred6: boolean; - export declare const inferred7: 1 | 2 | 3 & 4; - export declare const inferred8: ["test", 1]; - export declare const inferred9: [...string]; - export declare const inferred10: (1 | 2n)[]; - export declare const inferred11: (keyof string)[]; - export declare const inferred12: number; + error[unknown-var-type]: unknown type for variable in the public API + --> https://jsr.io/@scope/a/1.0.0/mod.ts:19:14 + | + 19 | export const asIs1 = [1, 2, 3]; + | ^^^^^ this variable's type could not be inferred because its initializer + | --------- contains this array literal, which can not be inferred unless marked 'as const' + | + = hint: add an explicit type annotation to the variable declaration + + info: all variables in the public API must have a known type + info: array literals without 'as const' can not be inferred because the type of the array can not be narrowed without a type checker + docs: https://jsr.io/go/slow-type-unknown-var-type + diff --git a/tests/specs/graph/jsr/dynamic_import.txt b/tests/specs/graph/jsr/dynamic_import.txt index 0648cbd9a..8618bdbc9 100644 --- a/tests/specs/graph/jsr/dynamic_import.txt +++ b/tests/specs/graph/jsr/dynamic_import.txt @@ -126,7 +126,7 @@ Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: } } } - const test: typeof import('./a.ts') = {} as never; + declare const test: typeof import('./a.ts'); export { test }; --- DTS --- declare const test: typeof import('./a.ts'); diff --git a/tests/specs/symbols/Classes01.txt b/tests/specs/symbols/Classes01.txt index 770d7275e..f808ce5a8 100644 --- a/tests/specs/symbols/Classes01.txt +++ b/tests/specs/symbols/Classes01.txt @@ -59,6 +59,14 @@ class ClassWithIndexSignatures { [value: string]: number; } +class ClassWithTypeParams { + prop: T; + + method(a: T): X { + return null as any; + } +} + # output file:///mod.ts: EsModuleInfo { module_id: ModuleId( @@ -71,74 +79,114 @@ file:///mod.ts: EsModuleInfo { "A", #2, ): 1, + ( + "c", + #3, + ): 4, ( "C", #2, - ): 4, + ): 5, ( "BBase", #2, - ): 5, + ): 6, ( "IBase", #2, - ): 6, + ): 7, ( "B", #2, - ): 7, + ): 8, + ( + "prop", + #4, + ): 10, + ( + "other", + #6, + ): 14, + ( + "private", + #7, + ): 16, + ( + "param", + #8, + ): 18, + ( + "param", + #9, + ): 19, ( "PropValue", #2, - ): 14, + ): 20, ( "ReturnValue", #2, - ): 15, + ): 21, ( "Param", #2, - ): 16, + ): 22, ( "PrivateParam", #2, - ): 17, + ): 23, ( "PrivateReturn", #2, - ): 18, + ): 24, ( "PrivateProp", #2, - ): 19, + ): 25, ( "CtorProp", #2, - ): 20, + ): 26, ( "OverloadParam", #2, - ): 21, + ): 27, ( "OverloadReturn", #2, - ): 22, + ): 28, ( "PrivateImplementationParam", #2, - ): 23, + ): 29, ( "PrivateImplementationReturn", #2, - ): 24, + ): 30, ( "ClassWithStatic", #2, - ): 25, + ): 31, ( "ClassWithIndexSignatures", #2, - ): 27, + ): 33, + ( + "ClassWithTypeParams", + #2, + ): 36, + ( + "T", + #11, + ): 37, + ( + "X", + #12, + ): 40, + ( + "a", + #12, + ): 41, }, symbols: { 0: Symbol { @@ -151,7 +199,7 @@ file:///mod.ts: EsModuleInfo { SymbolDecl { kind: Definition( SymbolNode( - "export class A {\n b: B;\n constructor(c: C) {\n }\n}\n\ninterface C {}\n\nclass BBase {\n\n}\n\ninterface IBase {\n}\n\nclass B extends BBase implements IBase {\n private constructor(prop: CtorProp) {}\n prop: PropValue;\n method(): ReturnValue {\n }\n\n method2(other: Param): void {\n }\n\n private asdf(private: PrivateParam): PrivateReturn {\n }\n\n private prop: PrivateProp;\n\n methodOverload(param: OverloadParam): OverloadReturn;\n methodOverload(param: PrivateImplementationParam): PrivateImplementationReturn {\n }\n\n #private: PrivateProp;\n #privateMethod(private: PrivateParam): PrivateReturn {\n }\n}\n\nclass PropValue {}\nclass ReturnValue {}\nclass Param {}\nclass PrivateParam {}\nclass PrivateReturn {}\nclass PrivateProp {}\nclass CtorProp {}\nclass OverloadParam {}\nclass OverloadReturn {}\nclass PrivateImplementationParam {}\nclass PrivateImplementationReturn {}\n\nclass ClassWithStatic {\n static prop: string;\n}\n\nclass ClassWithIndexSignatures {\n static [value: string]: number;\n [value: number]: string;\n [value: string]: number;\n}", + "export class A {\n b: B;\n constructor(c: C) {\n }\n}\n\ninterface C {}\n\nclass BBase {\n\n}\n\ninterface IBase {\n}\n\nclass B extends BBase implements IBase {\n private constructor(prop: CtorProp) {}\n prop: PropValue;\n method(): ReturnValue {\n }\n\n method2(other: Param): void {\n }\n\n private asdf(private: PrivateParam): PrivateReturn {\n }\n\n private prop: PrivateProp;\n\n methodOverload(param: OverloadParam): OverloadReturn;\n methodOverload(param: PrivateImplementationParam): PrivateImplementationReturn {\n }\n\n #private: PrivateProp;\n #privateMethod(private: PrivateParam): PrivateReturn {\n }\n}\n\nclass PropValue {}\nclass ReturnValue {}\nclass Param {}\nclass PrivateParam {}\nclass PrivateReturn {}\nclass PrivateProp {}\nclass CtorProp {}\nclass OverloadParam {}\nclass OverloadReturn {}\nclass PrivateImplementationParam {}\nclass PrivateImplementationReturn {}\n\nclass ClassWithStatic {\n static prop: string;\n}\n\nclass ClassWithIndexSignatures {\n static [value: string]: number;\n [value: number]: string;\n [value: string]: number;\n}\n\nclass ClassWithTypeParams {\n prop: T;\n\n method(a: T): X {\n return null as any;\n }\n}", ), ), range: SourceRange { @@ -159,7 +207,7 @@ file:///mod.ts: EsModuleInfo { 0, ), end: SourcePos( - 1033, + 1130, ), }, flags: 0, @@ -167,23 +215,24 @@ file:///mod.ts: EsModuleInfo { ], child_ids: { 1, - 4, 5, 6, 7, - 14, - 15, - 16, - 17, - 18, - 19, + 8, 20, 21, 22, 23, 24, 25, + 26, 27, + 28, + 29, + 30, + 31, + 33, + 36, }, exports: { "A": 1, @@ -291,6 +340,36 @@ file:///mod.ts: EsModuleInfo { 0, ), symbol_id: 4, + parent_id: Some( + 3, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "c", + ), + ), + range: SourceRange { + start: SourcePos( + 39, + ), + end: SourcePos( + 40, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 5: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 5, parent_id: Some( 0, ), @@ -316,11 +395,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 5: Symbol { + 6: Symbol { module_id: ModuleId( 0, ), - symbol_id: 5, + symbol_id: 6, parent_id: Some( 0, ), @@ -346,11 +425,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 6: Symbol { + 7: Symbol { module_id: ModuleId( 0, ), - symbol_id: 6, + symbol_id: 7, parent_id: Some( 0, ), @@ -376,11 +455,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 7: Symbol { + 8: Symbol { module_id: ModuleId( 0, ), - symbol_id: 7, + symbol_id: 8, parent_id: Some( 0, ), @@ -403,26 +482,26 @@ file:///mod.ts: EsModuleInfo { }, ], child_ids: { - 8, + 9, }, exports: { - "%%dg_ctor%%": 8, + "%%dg_ctor%%": 9, }, members: { - 9, - 10, 11, 12, 13, + 15, + 17, }, }, - 8: Symbol { + 9: Symbol { module_id: ModuleId( 0, ), - symbol_id: 8, + symbol_id: 9, parent_id: Some( - 7, + 8, ), decls: [ SymbolDecl { @@ -446,13 +525,43 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 9: Symbol { + 10: Symbol { module_id: ModuleId( 0, ), - symbol_id: 9, + symbol_id: 10, parent_id: Some( - 7, + 9, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "prop", + ), + ), + range: SourceRange { + start: SourcePos( + 172, + ), + end: SourcePos( + 176, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 11: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 11, + parent_id: Some( + 8, ), decls: [ SymbolDecl { @@ -492,13 +601,13 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 10: Symbol { + 12: Symbol { module_id: ModuleId( 0, ), - symbol_id: 10, + symbol_id: 12, parent_id: Some( - 7, + 8, ), decls: [ SymbolDecl { @@ -522,13 +631,13 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 11: Symbol { + 13: Symbol { module_id: ModuleId( 0, ), - symbol_id: 11, + symbol_id: 13, parent_id: Some( - 7, + 8, ), decls: [ SymbolDecl { @@ -552,13 +661,43 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 12: Symbol { + 14: Symbol { module_id: ModuleId( 0, ), - symbol_id: 12, + symbol_id: 14, parent_id: Some( - 7, + 13, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "other", + ), + ), + range: SourceRange { + start: SourcePos( + 251, + ), + end: SourcePos( + 256, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 15: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 15, + parent_id: Some( + 8, ), decls: [ SymbolDecl { @@ -582,13 +721,43 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 13: Symbol { + 16: Symbol { module_id: ModuleId( 0, ), - symbol_id: 13, + symbol_id: 16, parent_id: Some( - 7, + 15, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "private", + ), + ), + range: SourceRange { + start: SourcePos( + 293, + ), + end: SourcePos( + 300, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 17: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 17, + parent_id: Some( + 8, ), decls: [ SymbolDecl { @@ -628,11 +797,71 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 14: Symbol { + 18: Symbol { module_id: ModuleId( 0, ), - symbol_id: 14, + symbol_id: 18, + parent_id: Some( + 17, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "param", + ), + ), + range: SourceRange { + start: SourcePos( + 385, + ), + end: SourcePos( + 390, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 19: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 19, + parent_id: Some( + 17, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "param", + ), + ), + range: SourceRange { + start: SourcePos( + 441, + ), + end: SourcePos( + 446, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 20: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 20, parent_id: Some( 0, ), @@ -658,11 +887,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 15: Symbol { + 21: Symbol { module_id: ModuleId( 0, ), - symbol_id: 15, + symbol_id: 21, parent_id: Some( 0, ), @@ -688,11 +917,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 16: Symbol { + 22: Symbol { module_id: ModuleId( 0, ), - symbol_id: 16, + symbol_id: 22, parent_id: Some( 0, ), @@ -718,11 +947,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 17: Symbol { + 23: Symbol { module_id: ModuleId( 0, ), - symbol_id: 17, + symbol_id: 23, parent_id: Some( 0, ), @@ -748,11 +977,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 18: Symbol { + 24: Symbol { module_id: ModuleId( 0, ), - symbol_id: 18, + symbol_id: 24, parent_id: Some( 0, ), @@ -778,11 +1007,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 19: Symbol { + 25: Symbol { module_id: ModuleId( 0, ), - symbol_id: 19, + symbol_id: 25, parent_id: Some( 0, ), @@ -808,11 +1037,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 20: Symbol { + 26: Symbol { module_id: ModuleId( 0, ), - symbol_id: 20, + symbol_id: 26, parent_id: Some( 0, ), @@ -838,11 +1067,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 21: Symbol { + 27: Symbol { module_id: ModuleId( 0, ), - symbol_id: 21, + symbol_id: 27, parent_id: Some( 0, ), @@ -868,11 +1097,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 22: Symbol { + 28: Symbol { module_id: ModuleId( 0, ), - symbol_id: 22, + symbol_id: 28, parent_id: Some( 0, ), @@ -898,11 +1127,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 23: Symbol { + 29: Symbol { module_id: ModuleId( 0, ), - symbol_id: 23, + symbol_id: 29, parent_id: Some( 0, ), @@ -928,11 +1157,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 24: Symbol { + 30: Symbol { module_id: ModuleId( 0, ), - symbol_id: 24, + symbol_id: 30, parent_id: Some( 0, ), @@ -958,11 +1187,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 25: Symbol { + 31: Symbol { module_id: ModuleId( 0, ), - symbol_id: 25, + symbol_id: 31, parent_id: Some( 0, ), @@ -985,20 +1214,20 @@ file:///mod.ts: EsModuleInfo { }, ], child_ids: { - 26, + 32, }, exports: { - "prop": 26, + "prop": 32, }, members: {}, }, - 26: Symbol { + 32: Symbol { module_id: ModuleId( 0, ), - symbol_id: 26, + symbol_id: 32, parent_id: Some( - 25, + 31, ), decls: [ SymbolDecl { @@ -1022,11 +1251,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 27: Symbol { + 33: Symbol { module_id: ModuleId( 0, ), - symbol_id: 27, + symbol_id: 33, parent_id: Some( 0, ), @@ -1049,22 +1278,22 @@ file:///mod.ts: EsModuleInfo { }, ], child_ids: { - 28, + 34, }, exports: { - "%%dg_index%%": 28, + "%%dg_index%%": 34, }, members: { - 29, + 35, }, }, - 28: Symbol { + 34: Symbol { module_id: ModuleId( 0, ), - symbol_id: 28, + symbol_id: 34, parent_id: Some( - 27, + 33, ), decls: [ SymbolDecl { @@ -1088,13 +1317,13 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 29: Symbol { + 35: Symbol { module_id: ModuleId( 0, ), - symbol_id: 29, + symbol_id: 35, parent_id: Some( - 27, + 33, ), decls: [ SymbolDecl { @@ -1134,33 +1363,220 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, + 36: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 36, + parent_id: Some( + 0, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "class ClassWithTypeParams {\n prop: T;\n\n method(a: T): X {\n return null as any;\n }\n}", + ), + ), + range: SourceRange { + start: SourcePos( + 1035, + ), + end: SourcePos( + 1130, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: { + 38, + 39, + }, + }, + 37: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 37, + parent_id: Some( + 36, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "T", + ), + ), + range: SourceRange { + start: SourcePos( + 1061, + ), + end: SourcePos( + 1062, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 38: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 38, + parent_id: Some( + 36, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "prop: T;", + ), + ), + range: SourceRange { + start: SourcePos( + 1068, + ), + end: SourcePos( + 1076, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 39: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 39, + parent_id: Some( + 36, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "method(a: T): X {\n return null as any;\n }", + ), + ), + range: SourceRange { + start: SourcePos( + 1080, + ), + end: SourcePos( + 1128, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 40: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 40, + parent_id: Some( + 39, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "X", + ), + ), + range: SourceRange { + start: SourcePos( + 1087, + ), + end: SourcePos( + 1088, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 41: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 41, + parent_id: Some( + 39, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "a", + ), + ), + range: SourceRange { + start: SourcePos( + 1090, + ), + end: SourcePos( + 1091, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, }, } == symbol deps (types and exprs) == 2:19..24 [Id(("B", #2))] 3:27..50 [Id(("C", #2))] -7:109..599 [Id(("BBase", #2)), Id(("IBase", #2))] -8:152..190 [Id(("CtorProp", #2))] -9:193..209 [Id(("PropValue", #2))] -9:340..366 [Id(("PrivateProp", #2))] -10:212..239 [Id(("ReturnValue", #2))] -11:243..276 [Id(("Param", #2))] -12:280..336 [Id(("PrivateParam", #2)), Id(("PrivateReturn", #2))] -13:370..423 [Id(("OverloadParam", #2)), Id(("OverloadReturn", #2))] -13:426..510 [Id(("PrivateImplementationParam", #2)), Id(("PrivateImplementationReturn", #2))] +8:109..599 [Id(("BBase", #2)), Id(("IBase", #2))] +9:152..190 [Id(("CtorProp", #2))] +11:193..209 [Id(("PropValue", #2))] +11:340..366 [Id(("PrivateProp", #2))] +12:212..239 [Id(("ReturnValue", #2))] +13:243..276 [Id(("Param", #2))] +15:280..336 [Id(("PrivateParam", #2)), Id(("PrivateReturn", #2))] +17:370..423 [Id(("OverloadParam", #2)), Id(("OverloadReturn", #2))] +17:426..510 [Id(("PrivateImplementationParam", #2)), Id(("PrivateImplementationReturn", #2))] +38:1068..1076 [Id(("T", #11))] +39:1080..1128 [Id(("T", #11)), Id(("X", #12))] == symbol deps (types only) == 2:19..24 [Id(("B", #2))] 3:27..50 [Id(("C", #2))] -7:109..599 [Id(("BBase", #2)), Id(("IBase", #2))] -8:152..190 [Id(("CtorProp", #2))] -9:193..209 [Id(("PropValue", #2))] -9:340..366 [Id(("PrivateProp", #2))] -10:212..239 [Id(("ReturnValue", #2))] -11:243..276 [Id(("Param", #2))] -12:280..336 [Id(("PrivateParam", #2)), Id(("PrivateReturn", #2))] -13:370..423 [Id(("OverloadParam", #2)), Id(("OverloadReturn", #2))] -13:426..510 [Id(("PrivateImplementationParam", #2)), Id(("PrivateImplementationReturn", #2))] +8:109..599 [Id(("BBase", #2)), Id(("IBase", #2))] +9:152..190 [Id(("CtorProp", #2))] +11:193..209 [Id(("PropValue", #2))] +11:340..366 [Id(("PrivateProp", #2))] +12:212..239 [Id(("ReturnValue", #2))] +13:243..276 [Id(("Param", #2))] +15:280..336 [Id(("PrivateParam", #2)), Id(("PrivateReturn", #2))] +17:370..423 [Id(("OverloadParam", #2)), Id(("OverloadReturn", #2))] +17:426..510 [Id(("PrivateImplementationParam", #2)), Id(("PrivateImplementationReturn", #2))] +38:1068..1076 [Id(("T", #11))] +39:1080..1128 [Id(("T", #11)), Id(("X", #12))] == export definitions == [A]: file:///mod.ts:0..52 diff --git a/tests/specs/symbols/Functions01.txt b/tests/specs/symbols/Functions01.txt index 5815bf0bf..7e58f1baf 100644 --- a/tests/specs/symbols/Functions01.txt +++ b/tests/specs/symbols/Functions01.txt @@ -33,50 +33,74 @@ file:///mod.ts: EsModuleInfo { "test", #2, ): 1, + ( + "T", + #3, + ): 2, + ( + "param", + #3, + ): 3, ( "TypeParam", #2, - ): 2, + ): 4, ( "Param", #2, - ): 3, + ): 5, ( "Return", #2, - ): 4, + ): 6, ( "Default", #2, - ): 5, + ): 7, ( "overloaded", #2, - ): 6, + ): 8, + ( + "T", + #4, + ): 9, + ( + "param", + #4, + ): 10, + ( + "T", + #6, + ): 11, + ( + "param", + #6, + ): 12, ( "OverloadTypeParam", #2, - ): 7, + ): 13, ( "OverloadParam", #2, - ): 8, + ): 14, ( "OverloadReturn", #2, - ): 9, + ): 15, ( "PrivateTypeParam", #2, - ): 10, + ): 16, ( "PrivateParam", #2, - ): 11, + ): 17, ( "PrivateReturn", #2, - ): 12, + ): 18, }, symbols: { 0: Symbol { @@ -105,21 +129,21 @@ file:///mod.ts: EsModuleInfo { ], child_ids: { 1, - 2, - 3, 4, 5, 6, 7, 8, - 9, - 10, - 11, - 12, + 13, + 14, + 15, + 16, + 17, + 18, }, exports: { "test": 1, - "overloaded": 6, + "overloaded": 8, }, members: {}, }, @@ -158,6 +182,66 @@ file:///mod.ts: EsModuleInfo { 0, ), symbol_id: 2, + parent_id: Some( + 1, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "T", + ), + ), + range: SourceRange { + start: SourcePos( + 21, + ), + end: SourcePos( + 22, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 3: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 3, + parent_id: Some( + 1, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "param", + ), + ), + range: SourceRange { + start: SourcePos( + 52, + ), + end: SourcePos( + 57, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 4: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 4, parent_id: Some( 0, ), @@ -183,11 +267,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 3: Symbol { + 5: Symbol { module_id: ModuleId( 0, ), - symbol_id: 3, + symbol_id: 5, parent_id: Some( 0, ), @@ -213,11 +297,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 4: Symbol { + 6: Symbol { module_id: ModuleId( 0, ), - symbol_id: 4, + symbol_id: 6, parent_id: Some( 0, ), @@ -243,11 +327,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 5: Symbol { + 7: Symbol { module_id: ModuleId( 0, ), - symbol_id: 5, + symbol_id: 7, parent_id: Some( 0, ), @@ -273,11 +357,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 6: Symbol { + 8: Symbol { module_id: ModuleId( 0, ), - symbol_id: 6, + symbol_id: 8, parent_id: Some( 0, ), @@ -335,11 +419,131 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 7: Symbol { + 9: Symbol { module_id: ModuleId( 0, ), - symbol_id: 7, + symbol_id: 9, + parent_id: Some( + 8, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "T", + ), + ), + range: SourceRange { + start: SourcePos( + 228, + ), + end: SourcePos( + 229, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 10: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 10, + parent_id: Some( + 8, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "param", + ), + ), + range: SourceRange { + start: SourcePos( + 257, + ), + end: SourcePos( + 262, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 11: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 11, + parent_id: Some( + 8, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "T", + ), + ), + range: SourceRange { + start: SourcePos( + 361, + ), + end: SourcePos( + 362, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 12: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 12, + parent_id: Some( + 8, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "param", + ), + ), + range: SourceRange { + start: SourcePos( + 389, + ), + end: SourcePos( + 394, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 13: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 13, parent_id: Some( 0, ), @@ -365,11 +569,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 8: Symbol { + 14: Symbol { module_id: ModuleId( 0, ), - symbol_id: 8, + symbol_id: 14, parent_id: Some( 0, ), @@ -395,11 +599,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 9: Symbol { + 15: Symbol { module_id: ModuleId( 0, ), - symbol_id: 9, + symbol_id: 15, parent_id: Some( 0, ), @@ -425,11 +629,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 10: Symbol { + 16: Symbol { module_id: ModuleId( 0, ), - symbol_id: 10, + symbol_id: 16, parent_id: Some( 0, ), @@ -455,11 +659,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 11: Symbol { + 17: Symbol { module_id: ModuleId( 0, ), - symbol_id: 11, + symbol_id: 17, parent_id: Some( 0, ), @@ -485,11 +689,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 12: Symbol { + 18: Symbol { module_id: ModuleId( 0, ), - symbol_id: 12, + symbol_id: 18, parent_id: Some( 0, ), @@ -519,13 +723,13 @@ file:///mod.ts: EsModuleInfo { } == symbol deps (types and exprs) == 1:0..77 [Id(("TypeParam", #2)), Id(("Default", #2)), Id(("Param", #2)), Id(("Return", #2))] -6:201..295 [Id(("OverloadTypeParam", #2)), Id(("OverloadParam", #2)), Id(("OverloadReturn", #2))] -6:334..428 [Id(("PrivateTypeParam", #2)), Id(("PrivateParam", #2)), Id(("PrivateReturn", #2))] +8:201..295 [Id(("OverloadTypeParam", #2)), Id(("OverloadParam", #2)), Id(("OverloadReturn", #2))] +8:334..428 [Id(("PrivateTypeParam", #2)), Id(("PrivateParam", #2)), Id(("PrivateReturn", #2))] == symbol deps (types only) == 1:0..77 [Id(("TypeParam", #2)), Id(("Default", #2)), Id(("Param", #2)), Id(("Return", #2))] -6:201..295 [Id(("OverloadTypeParam", #2)), Id(("OverloadParam", #2)), Id(("OverloadReturn", #2))] -6:334..428 [Id(("PrivateTypeParam", #2)), Id(("PrivateParam", #2)), Id(("PrivateReturn", #2))] +8:201..295 [Id(("OverloadTypeParam", #2)), Id(("OverloadParam", #2)), Id(("OverloadReturn", #2))] +8:334..428 [Id(("PrivateTypeParam", #2)), Id(("PrivateParam", #2)), Id(("PrivateReturn", #2))] == export definitions == [test]: file:///mod.ts:0..77 diff --git a/tests/specs/symbols/class_private_ctor_param_props.txt b/tests/specs/symbols/class_private_ctor_param_props.txt index 482502cb8..fee42f42b 100644 --- a/tests/specs/symbols/class_private_ctor_param_props.txt +++ b/tests/specs/symbols/class_private_ctor_param_props.txt @@ -23,14 +23,18 @@ file:///mod.ts: EsModuleInfo { "Class", #2, ): 1, + ( + "regularParam", + #3, + ): 5, ( "PublicClass", #2, - ): 5, + ): 6, ( "PrivateClass", #2, - ): 6, + ): 7, }, symbols: { 0: Symbol { @@ -59,8 +63,8 @@ file:///mod.ts: EsModuleInfo { ], child_ids: { 1, - 5, 6, + 7, }, exports: { "Class": 1, @@ -199,6 +203,36 @@ file:///mod.ts: EsModuleInfo { 0, ), symbol_id: 5, + parent_id: Some( + 2, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "regularParam", + ), + ), + range: SourceRange { + start: SourcePos( + 119, + ), + end: SourcePos( + 131, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 6: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 6, parent_id: Some( 0, ), @@ -224,11 +258,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 6: Symbol { + 7: Symbol { module_id: ModuleId( 0, ), - symbol_id: 6, + symbol_id: 7, parent_id: Some( 0, ), diff --git a/tests/specs/symbols/declaration_merging01.txt b/tests/specs/symbols/declaration_merging01.txt index 24283e0d1..54406b522 100644 --- a/tests/specs/symbols/declaration_merging01.txt +++ b/tests/specs/symbols/declaration_merging01.txt @@ -48,14 +48,18 @@ file:///mod.ts: EsModuleInfo { "mixColor", #4, ): 4, + ( + "colorName", + #5, + ): 5, ( "Test", #2, - ): 5, + ): 6, ( "other", #7, - ): 6, + ): 7, }, symbols: { 0: Symbol { @@ -85,12 +89,12 @@ file:///mod.ts: EsModuleInfo { child_ids: { 1, 3, - 5, + 6, }, exports: { - "Album": 7, - "Color": 8, - "Test": 9, + "Album": 8, + "Color": 9, + "Test": 10, }, members: {}, }, @@ -259,6 +263,36 @@ file:///mod.ts: EsModuleInfo { 0, ), symbol_id: 5, + parent_id: Some( + 4, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "colorName", + ), + ), + range: SourceRange { + start: SourcePos( + 145, + ), + end: SourcePos( + 154, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 6: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 6, parent_id: Some( 0, ), @@ -297,20 +331,20 @@ file:///mod.ts: EsModuleInfo { }, ], child_ids: { - 6, + 7, }, exports: { - "other": 6, + "other": 7, }, members: {}, }, - 6: Symbol { + 7: Symbol { module_id: ModuleId( 0, ), - symbol_id: 6, + symbol_id: 7, parent_id: Some( - 5, + 6, ), decls: [ SymbolDecl { @@ -334,11 +368,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 7: Symbol { + 8: Symbol { module_id: ModuleId( 0, ), - symbol_id: 7, + symbol_id: 8, parent_id: Some( 0, ), @@ -365,11 +399,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 8: Symbol { + 9: Symbol { module_id: ModuleId( 0, ), - symbol_id: 8, + symbol_id: 9, parent_id: Some( 0, ), @@ -396,11 +430,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 9: Symbol { + 10: Symbol { module_id: ModuleId( 0, ), - symbol_id: 9, + symbol_id: 10, parent_id: Some( 0, ), diff --git a/tests/specs/symbols/function_overloads01.txt b/tests/specs/symbols/function_overloads01.txt index 0b616fddd..91118481b 100644 --- a/tests/specs/symbols/function_overloads01.txt +++ b/tests/specs/symbols/function_overloads01.txt @@ -26,18 +26,42 @@ file:///mod.ts: EsModuleInfo { "test", #2, ): 1, + ( + "value", + #3, + ): 2, + ( + "value", + #4, + ): 3, + ( + "value", + #5, + ): 4, ( "Inner", #2, - ): 2, + ): 5, ( "inner", #6, - ): 3, + ): 6, + ( + "value", + #7, + ): 7, + ( + "value", + #8, + ): 8, + ( + "value", + #9, + ): 9, ( "InnerInner", #2, - ): 4, + ): 10, }, symbols: { 0: Symbol { @@ -66,11 +90,11 @@ file:///mod.ts: EsModuleInfo { ], child_ids: { 1, - 2, + 5, }, exports: { "test": 1, - "InnerInner": 5, + "InnerInner": 11, }, members: {}, }, @@ -141,6 +165,96 @@ file:///mod.ts: EsModuleInfo { 0, ), symbol_id: 2, + parent_id: Some( + 1, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "value", + ), + ), + range: SourceRange { + start: SourcePos( + 21, + ), + end: SourcePos( + 26, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 3: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 3, + parent_id: Some( + 1, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "value", + ), + ), + range: SourceRange { + start: SourcePos( + 58, + ), + end: SourcePos( + 63, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 4: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 4, + parent_id: Some( + 1, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "value", + ), + ), + range: SourceRange { + start: SourcePos( + 95, + ), + end: SourcePos( + 100, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 5: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 5, parent_id: Some( 0, ), @@ -163,20 +277,20 @@ file:///mod.ts: EsModuleInfo { }, ], child_ids: { - 3, + 6, }, exports: { - "inner": 3, + "inner": 6, }, members: {}, }, - 3: Symbol { + 6: Symbol { module_id: ModuleId( 0, ), - symbol_id: 3, + symbol_id: 6, parent_id: Some( - 2, + 5, ), decls: [ SymbolDecl { @@ -232,11 +346,101 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 4: Symbol { + 7: Symbol { module_id: ModuleId( 0, ), - symbol_id: 4, + symbol_id: 7, + parent_id: Some( + 6, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "value", + ), + ), + range: SourceRange { + start: SourcePos( + 166, + ), + end: SourcePos( + 171, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 8: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 8, + parent_id: Some( + 6, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "value", + ), + ), + range: SourceRange { + start: SourcePos( + 206, + ), + end: SourcePos( + 211, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 9: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 9, + parent_id: Some( + 6, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "value", + ), + ), + range: SourceRange { + start: SourcePos( + 246, + ), + end: SourcePos( + 251, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, + 10: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 10, parent_id: Some( 0, ), @@ -266,11 +470,11 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, - 5: Symbol { + 11: Symbol { module_id: ModuleId( 0, ), - symbol_id: 5, + symbol_id: 11, parent_id: Some( 0, ), diff --git a/tests/specs/symbols/ts_namespace_export01.txt b/tests/specs/symbols/ts_namespace_export01.txt index c5109ed77..2bc65d0e0 100644 --- a/tests/specs/symbols/ts_namespace_export01.txt +++ b/tests/specs/symbols/ts_namespace_export01.txt @@ -19,6 +19,10 @@ file:///mod.ts: EsModuleInfo { "isPrime", #2, ): 1, + ( + "x", + #3, + ): 2, }, symbols: { 0: Symbol { @@ -83,6 +87,36 @@ file:///mod.ts: EsModuleInfo { exports: {}, members: {}, }, + 2: Symbol { + module_id: ModuleId( + 0, + ), + symbol_id: 2, + parent_id: Some( + 1, + ), + decls: [ + SymbolDecl { + kind: Definition( + SymbolNode( + "x", + ), + ), + range: SourceRange { + start: SourcePos( + 24, + ), + end: SourcePos( + 25, + ), + }, + flags: 0, + }, + ], + child_ids: {}, + exports: {}, + members: {}, + }, }, } == export definitions == diff --git a/tests/specs_test.rs b/tests/specs_test.rs index 633ad00fd..020c022fa 100644 --- a/tests/specs_test.rs +++ b/tests/specs_test.rs @@ -1,10 +1,9 @@ // Copyright 2018-2024 the Deno authors. MIT license. use std::collections::BTreeMap; -use std::panic::AssertUnwindSafe; - use std::collections::HashMap; use std::fmt::Write; +use std::panic::AssertUnwindSafe; use deno_ast::diagnostics::Diagnostic; use deno_ast::emit;