diff --git a/Cargo.lock b/Cargo.lock index 62b920b49d06..b3cc4ffbb335 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1361,7 +1361,6 @@ dependencies = [ "bun_core", "bun_paths", "bun_sema_standalone", - "bun_semver", "bun_threading", "bun_wyhash", "hashbrown 0.15.5", diff --git a/src/ast/lexer_tables.rs b/src/ast/lexer_tables.rs index ac589a36624d..63cd866adbd1 100644 --- a/src/ast/lexer_tables.rs +++ b/src/ast/lexer_tables.rs @@ -52,6 +52,7 @@ pub enum T { TLessThan, TLessThanEquals, TLessThanLessThan, + TLessThanSlash, // scanned for the type checker only, in a file with JSX TMinus, TMinusMinus, TOpenBrace, @@ -326,6 +327,7 @@ pub static TOKEN_TO_STRING: TokenEnumType = TokenEnumType({ token_enums[T::TLessThan as usize] = b"\"<\""; token_enums[T::TLessThanEquals as usize] = b"\"<=\""; token_enums[T::TLessThanLessThan as usize] = b"\"<<\""; + token_enums[T::TLessThanSlash as usize] = b"\" { pub(crate) token: T, @@ -239,12 +247,10 @@ pub struct Lexer<'a> { pub(crate) tolerant: bool, /// `Options::is_javascript` pub(crate) is_javascript: bool, + /// `languageVariant == LanguageVariantJSX`. Set for the type checker only. + pub(crate) is_jsx: bool, /// Number of consecutive error recoveries at the same position. pub(crate) stuck: u32, - /// Tolerant mode: the number of errors that were not logged because the log was disabled. - /// TypeScript keeps the errors of a speculative parse that succeeds (`mark`, `rewind`), so a - /// speculative parse during which this count changed must be repeated with the log enabled. - pub(crate) swallowed: u32, /// Without `EscapeSequenceScanningFlagsReportInvalidEscapeErrors`: an escape sequence that is /// an error elsewhere is not reported, and decodes to its own source text. is_under_tag: bool, @@ -260,6 +266,8 @@ pub struct Lexer<'a> { /// Tolerant mode: start of the most recent unterminated string or template /// (`TokenFlagsUnterminated`). pub(crate) unterminated_at: usize, + /// Tolerant mode: end of the most recent unterminated string or regular expression. + unterminated_end: usize, pub(crate) comments_to_preserve_before: Vec, pub(crate) code_point: CodePoint, pub(crate) identifier: &'a [u8], @@ -292,8 +300,9 @@ pub struct Lexer<'a> { /// `skipJSDocLeadingAsterisks`: a type in a JSDoc comment is being scanned, where the first `*` of a line is trivia. Set for the /// type checker only. pub(crate) skips_jsdoc_asterisks: bool, - /// End of the `*` most recently skipped as trivia. - jsdoc_asterisk_end: usize, + /// `TokenFlagsPrecedingJSDocLeadingAsterisks`: where a `*` was skipped as trivia. A speculative + /// parse that is repeated lists it again. + pub(crate) jsdoc_asterisks: Vec, } impl<'a> LexerLog<'a> for Lexer<'a> { @@ -1179,7 +1188,6 @@ impl<'a> Lexer<'a> { ) { debug_assert!(self.tolerant); if self.is_log_disabled { - self.swallowed += 1; return; } // One empty argument is not no argument: `JSX element '' has no corresponding closing tag`. @@ -1188,19 +1196,43 @@ impl<'a> Lexer<'a> { } else { what }; - let logged_before = self.log().msgs.len(); if kind == TypeScriptKind::Parse { - let _ = self.add_range_error(r, format_args!("")); - } else { - self.log() - .add_range_error_fmt(Some(self.source), r, format_args!("")); - } - // Dropped if the previous error was at the same position. - if let Some(msg) = self.log().msgs.get_mut(logged_before) { - // The bytes as they are: `Format` replaces what is not valid UTF-8. - msg.data.text = what.unwrap_or_default().to_vec().into(); - msg.metadata = bun_ast::Metadata::TypeScript { code, kind }; - } + // `parseErrorAtRange`: dropped if the previous error was at the same position. + if r.loc.eql(self.prev_error_loc) { + return; + } + self.prev_error_loc = r.loc; + } + // FOR SPEED: the type checker reads the offset and the length (`sema::diagnostic`). The line, the column and the text of + // the line take a scan of the source and an allocation, and a speculative parse drops most of what it logs. + let location = bun_ast::Location { + file: std::borrow::Cow::Borrowed(b""), + namespace: std::borrow::Cow::Borrowed(b""), + line_text: None, + length: match r.len { + _ if r.is_empty() => 0, + len if len > -1 => len as usize, + _ => 1, + }, + offset: match r.is_empty() { + true => 0, + false => r.loc.start.max(0) as usize, + }, + line: 0, + column: 0, + }; + let log = self.log(); + log.errors += 1; + log.add_msg(bun_ast::Msg { + kind: bun_ast::Kind::Err, + data: bun_ast::Data { + // The bytes as they are: `Format` replaces what is not valid UTF-8. + text: what.unwrap_or_default().to_vec().into(), + location: Some(location), + }, + metadata: bun_ast::Metadata::TypeScript { code, kind }, + ..Default::default() + }); } /// The range from `start` to the end of the previous token. @@ -1257,8 +1289,7 @@ impl<'a> Lexer<'a> { } /// Whether scanning may continue after an error that TypeScript's scanner only reports - /// (`errorAt`): logs `code` at `at`. The scanner always returns a token, so a speculative parse - /// goes on too, and keeps the error if it succeeds (`swallowed`). + /// (`errorAt`): logs `code` at `at`. The scanner always returns a token. #[cold] #[inline(never)] fn tolerate(&mut self, at: usize, len: usize, code: u32) -> bool { @@ -1295,6 +1326,7 @@ impl<'a> Lexer<'a> { self.scan_string_value(self.start + 1, text); } self.unterminated_at = self.start; + self.unterminated_end = at; // `scanEscapeSequence`: a backslash followed by nothing, also in a tagged template. let ends_in_backslash = text.iter().rev().take_while(|&&c| c == b'\\').count() % 2 == 1; let code = if ends_in_backslash { @@ -1615,29 +1647,35 @@ impl<'a> Lexer<'a> { } } - /// The range of the current token, an identifier or a keyword, if it contains an escape: for + /// The current token, an identifier or a keyword, if it contains an escape: for /// `keyword_was_taken`. `None` outside tolerant mode. #[inline] - pub(crate) fn escaped_word(&self) -> Option { - (self.tolerant && self.has_unicode_escape()).then(|| self.range()) + pub(crate) fn escaped_word(&self) -> Option { + (self.tolerant && self.has_unicode_escape()).then(|| EscapedWord { + range: self.range(), + prev_error_loc: self.prev_error_loc, + }) } /// `nextToken` for a keyword that `next` has consumed, once the tokens after it have shown that /// it is no name. `word`: its `escaped_word`. #[inline] - pub(crate) fn keyword_was_taken(&mut self, word: Option) { - if let Some(r) = word { - self.escaped_keyword_was_taken(r); + pub(crate) fn keyword_was_taken(&mut self, word: Option) { + if let Some(word) = word { + self.escaped_keyword_was_taken(word); } } /// The error precedes those reported since the keyword was consumed. #[cold] #[inline(never)] - fn escaped_keyword_was_taken(&mut self, r: Range) { + fn escaped_keyword_was_taken(&mut self, word: EscapedWord) { let last = self.prev_error_loc; - self.ts_error(r, 1260); - self.prev_error_loc = last; + self.prev_error_loc = word.prev_error_loc; + self.ts_error(word.range, 1260); + if last != word.prev_error_loc { + self.prev_error_loc = last; + } } /// Whether the token is the reserved word `keyword`. TypeScript's scanner returns the keyword @@ -2056,6 +2094,11 @@ impl<'a> Lexer<'a> { self.split_token(T::TEquals); self.maybe_expand_equals()?; } + // `Scan` continues from the second "<", which may start a longer token. + T::TLessThanLessThan if self.tolerant => { + self.move_to(self.start + 1); + self.next()?; + } T::TLessThanLessThan => { self.split_token(T::TLessThan); } @@ -2086,6 +2129,17 @@ impl<'a> Lexer<'a> { self.maybe_expand_equals()?; } + // `Scan` joins a `>` with nothing: the second one closes the tag, and the text of the + // element follows it. + T::TGreaterThanGreaterThanEquals + | T::TGreaterThanGreaterThanGreaterThanEquals + | T::TGreaterThanGreaterThanGreaterThan + if IS_INSIDE_JSX_ELEMENT && self.tolerant => + { + self.split_token(T::TGreaterThan); + self.move_to(self.start + 1); + } + T::TGreaterThanGreaterThanEquals => { self.split_token(T::TGreaterThanEquals); } @@ -2164,6 +2218,10 @@ impl<'a> Lexer<'a> { _ => {} } } + // `Scan`: a shebang is trivia. + if self.tolerant { + continue; + } self.identifier = self.raw(); } else { // "#foo" @@ -2570,6 +2628,10 @@ impl<'a> Lexer<'a> { self.token = T::TLessThan; } + 0x2F if self.is_jsx && contents.get(self.current) != Some(&b'*') => { + self.step_with(contents); + self.token = T::TLessThanSlash; + } _ => { self.token = T::TLessThan; } @@ -2823,15 +2885,15 @@ impl<'a> Lexer<'a> { } // Only whitespace since the previously skipped `*`, which was in the leading trivia of the // same token. - if self.jsdoc_asterisk_end != 0 + if let Some(&skipped) = self.jsdoc_asterisks.last() && self .contents - .get(self.jsdoc_asterisk_end..self.start) + .get(skipped as usize + 1..self.start) .is_some_and(|between| trailing_whitespace_len(between) == between.len()) { return false; } - self.jsdoc_asterisk_end = self.end; + self.jsdoc_asterisks.push(self.start as u32); true } @@ -2869,9 +2931,6 @@ impl<'a> Lexer<'a> { } }; - if self.tolerant && self.is_log_disabled { - self.swallowed += 1; - } self.add_range_error( self.range(), format_args!("Unexpected {}", bstr::BStr::new(found)), @@ -3316,13 +3375,14 @@ impl<'a> Lexer<'a> { is_log_disabled: false, tolerant: false, is_javascript: false, + is_jsx: false, stuck: 0, - swallowed: 0, is_under_tag: false, await_name_seen: false, list_contexts: 0, rescanned_greater_than_at: usize::MAX, unterminated_at: usize::MAX, + unterminated_end: usize::MAX, comments_to_preserve_before: Vec::new(), code_point: -1, identifier: b"", @@ -3348,7 +3408,7 @@ impl<'a> Lexer<'a> { comment_directives: Vec::new(), last_line_start: 0, skips_jsdoc_asterisks: false, - jsdoc_asterisk_end: 0, + jsdoc_asterisks: Vec::new(), } } @@ -3566,6 +3626,7 @@ impl<'a> Lexer<'a> { 1161, ); self.regex_flags_start = None; + self.unterminated_end = end; self.move_to(end); } @@ -3839,15 +3900,6 @@ impl<'a> Lexer<'a> { Ok(()) } - /// `KindLessThanSlashToken`: in a JSX file `Scan` scans ` bool { - self.token == T::TLessThan - && self.code_point == 0x2F - && self.contents.get(self.current) != Some(&b'*') - } - /// `ScanJsxAttributeValue`, at the `=` of an attribute. A quote starts a JSX string only if /// nothing but white space precedes it. Anything else, a comment too, is left to `Scan`. pub(crate) fn next_jsx_attribute_value(&mut self) -> Result<(), Error> { @@ -4936,10 +4988,11 @@ impl<'a> Lexer<'a> { }); self.number = val as f64; // After a `-` token, whatever trivia follows it, the error starts one byte earlier, - // whatever that byte is. A run of `-` of odd length ends with that token. + // whatever that byte is. A run of `-` of odd length ends with that token, unless it + // is the text of a literal that has no end. let before = &text[..self.token_full_start]; - let is_after_minus = - before.iter().rev().take_while(|&&ch| ch == b'-').count() % 2 == 1; + let is_after_minus = self.unterminated_end != self.token_full_start + && before.iter().rev().take_while(|&&ch| ch == b'-').count() % 2 == 1; // Octal literals are not allowed. let sign = if is_after_minus { "-" } else { "" }; let suggestion = format!("{sign}0o{val:o}").into_bytes(); diff --git a/src/js_parser/p.rs b/src/js_parser/p.rs index dc3c9ee4fe7c..a613d9f21d05 100644 --- a/src/js_parser/p.rs +++ b/src/js_parser/p.rs @@ -274,6 +274,12 @@ pub struct P<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool pub(crate) await_was_refused: bool, /// Tolerant mode: the loop of `reparseTopLevelAwait` continues to the end of the file. pub(crate) reparses_rest_of_file: bool, + /// Tolerant mode: an `await` in the top-level statement being parsed was read outside the + /// [Await] context, as an identifier. + pub(crate) await_read_as_identifier: bool, + /// Tolerant mode: the top-level statements that have one and that `reparseTopLevelAwait` + /// parses again. Those listed before the parse starts are parsed that way. + pub(crate) statements_with_await_in_names: Vec, /// Tolerant mode: the decorators saved by `note_stray_decorators`, until the statement list /// being parsed takes them. pub(crate) stray_decorators: Vec, @@ -8448,17 +8454,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } } - /// [`Self::restore_parser_snapshot`] for a caller that keeps the nodes parsed since the - /// snapshot: their notes are not rolled back. - pub(crate) fn restore_parser_snapshot_but_for_notes( - &mut self, - mut snapshot: ParserSnapshot<'a>, - ) { - self.release_type_syntax_checkpoint(&snapshot.noted); - snapshot.noted = self.type_syntax_checkpoint(); - self.restore_parser_snapshot(snapshot); - } - /// The speculative parse since [`Self::parser_snapshot`] succeeded. #[inline] pub(crate) fn release_parser_snapshot(&mut self, snapshot: &ParserSnapshot<'a>) { @@ -9953,6 +9948,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> has_es_module_syntax: false, await_was_refused: false, reparses_rest_of_file: false, + await_read_as_identifier: false, + statements_with_await_in_names: Vec::new(), stray_decorators: Vec::new(), top_level_await_keyword: bun_ast::Range::NONE, fn_or_arrow_data_parse, diff --git a/src/js_parser/parse/lists.rs b/src/js_parser/parse/lists.rs index 6abf6a0e80b2..97c0984af443 100644 --- a/src/js_parser/parse/lists.rs +++ b/src/js_parser/parse/lists.rs @@ -196,7 +196,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } /// `GetIdentifierToken`: a reserved word also if it is written with an escape. - fn token(&self) -> T { + pub(crate) fn token(&self) -> T { match self.lexer.token { T::TEscapedKeyword => { crate::lexer::keyword(self.lexer.identifier).unwrap_or(T::TIdentifier) @@ -240,7 +240,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> /// `IsModifierKind` pub(crate) fn is_modifier_kind(&self) -> bool { - match self.lexer.token { + match self.token() { T::TConst | T::TDefault | T::TExport | T::TIn => true, T::TIdentifier => match Modifier::find(self.word()) { Some(Modifier::PGet | Modifier::PSet) => false, @@ -281,9 +281,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[cold] #[inline(never)] pub(crate) fn is_start_of_expression_or_shift_assign(&mut self) -> bool { - if self.is_at_less_than_slash_token() { - return false; - } self.is_start_of_expression() || matches!( self.lexer.token, @@ -291,11 +288,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> ) && self.lexer.start != self.lexer.rescanned_greater_than_at } - /// `KindLessThanSlashToken`: ` bool { - self.lexer.token == T::TLessThan && self.is_jsx_enabled() && self.lexer.is_less_than_slash() - } - /// `isStartOfDeclaration` (lookahead with `scanStartOfDeclaration`). #[cold] #[inline(never)] @@ -553,7 +545,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[cold] #[inline(never)] pub(crate) fn is_start_of_type(&mut self, in_start_of_parameter: bool) -> bool { - match self.lexer.token { + match self.token() { T::TVoid | T::TNull | T::TThis @@ -611,9 +603,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> /// `isHeritageClause` fn is_heritage_clause(&self) -> bool { - self.lexer.token == T::TExtends - || self.word() == b"implements" - || (self.lexer.token == T::TEscapedKeyword && self.lexer.identifier == b"extends") + self.token() == T::TExtends || self.word() == b"implements" } /// `isHeritageClauseExtendsOrImplementsKeyword` @@ -626,14 +616,14 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[cold] #[inline(never)] pub(crate) fn is_list_element(&mut self, kind: ListKind, recovering: bool) -> bool { - let token = self.lexer.token; + let token = self.token(); match kind { ListKind::SourceElements | ListKind::BlockStatements | ListKind::SwitchClauseStatements => { !(token == T::TSemicolon && recovering) && self.is_start_of_statement() } - ListKind::SwitchClauses => matches!(self.token(), T::TCase | T::TDefault), + ListKind::SwitchClauses => matches!(token, T::TCase | T::TDefault), ListKind::TypeMembers => self.is_type_member_start(), ListKind::ClassMembers => { self.is_class_member_start() || token == T::TSemicolon && !recovering @@ -788,6 +778,19 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> found } + /// `newIdentifier`, at the name: `statementHasAwaitIdentifier`. An `await` that the first parse + /// of a top-level statement takes for a name has `reparseTopLevelAwait` parse the statement + /// again in the [Await] context (`statements_with_await_in_names`). + pub(crate) fn new_identifier(&mut self) { + if self.is_tolerant() && self.fn_or_arrow_data_parse.is_top_level && self.is_await_keyword() + { + self.lexer.await_name_seen = true; + self.await_read_as_identifier = true; + // `parse_for_sema` reparses a script, with `await` as an identifier, if this is set. + self.top_level_await_keyword = self.lexer.range(); + } + } + /// `await` where it is not an identifier (`isIdentifier`): in an [Await] context, which the top /// level of a module is when TypeScript reparses the statement. fn is_await_keyword(&self) -> bool { @@ -859,9 +862,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.lexer.put_up_with(before)?; return Ok(true); } - if self.is_at_less_than_slash_token() { - self.lexer.step(); - } self.lexer.next()?; if !self.lexer.is_log_disabled { let next = self.lexer.loc(); diff --git a/src/js_parser/parse/mod.rs b/src/js_parser/parse/mod.rs index 65c2ce24fdfd..5b4b565c723d 100644 --- a/src/js_parser/parse/mod.rs +++ b/src/js_parser/parse/mod.rs @@ -70,6 +70,19 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.parse_expr_common(level, None, EFlags::None, &mut expr)?; Ok(expr) } + /// `parseExpressionAllowIn`, `doInContext(p, NodeFlagsDisallowInContext, false, ..)`. + /// TypeScript's parser stays in the context of the head of a "for" through function bodies, + /// class bodies, and array and object literals, and leaves it here. + #[inline] + pub(crate) fn parse_expr_allow_in(&mut self, level: Level) -> Result { + if !self.is_tolerant() { + return self.parse_expr(level); + } + let old_allow_in = core::mem::replace(&mut self.allow_in, true); + let expr = self.parse_expr(level); + self.allow_in = old_allow_in; + expr + } #[inline] pub(crate) fn parse_expr_with_flags( &mut self, @@ -216,10 +229,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.expect(T::TOpenBrace)?; let mut properties = BumpVec::::new_in(p.arena); - // Allow "in" and private fields inside class bodies + // Allow "in" and private fields inside class bodies. (`parseClassMembers` leaves the context + // as it is: see `parse_expr_allow_in`.) let old_allow_in = p.allow_in; let old_allow_private_identifiers = p.allow_private_identifiers; - p.allow_in = true; + p.allow_in = old_allow_in || !p.is_tolerant(); p.allow_private_identifiers = true; // A scope is needed for private identifiers @@ -681,7 +695,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[inline(never)] fn parse_jsx_attribute_value_without_braces(&mut self) -> Result, Error> { let p = self; - if p.is_at_less_than_token() { + if p.lexer.token == T::TLessThan { let first = p.lexer.loc(); return p.parse_jsx_elements_in_attribute_value(first).map(Some); } @@ -694,11 +708,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(None) } - /// `KindLessThanToken`, which " bool { - self.lexer.token == T::TLessThan && !self.lexer.is_less_than_slash() - } - /// `parseJsxElementOrSelfClosingElementOrFragment` in an expression context, at its "<". /// Another element that follows immediately is reported at `first`, the start of the first of /// them, and joined to this one by a comma operator. @@ -715,7 +724,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if p.lexer.token == T::TGreaterThan { p.lexer.next_inside_jsx_element()?; } - if !p.is_at_less_than_token() { + if p.lexer.token != T::TLessThan { return Ok(element); } if p.lexer.is_log_disabled { @@ -864,6 +873,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> }; p.fn_or_arrow_data_parse.allow_yield = AwaitOrYield::AllowIdent; p.fn_or_arrow_data_parse.is_top_level = false; + // `parseParameterEx` parses an initializer in the context of the arrow function. + p.allow_in = old_allow_in; } // Scan over the comma-separated arguments or expressions @@ -890,12 +901,18 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> && p.is_tolerant() && attempt != ArrowAttempt::NeverArrow && level.lte(Level::Assign) - && p.is_modifier_kind() - && p.parse_arrow_parameter_modifiers(items_list.len(), &mut parameter_modifiers)? + && (p.is_modifier_kind() || (p.lexer.token == T::TAt && are_parameters)) + && p.parse_arrow_parameter_modifiers( + items_list.len(), + &old_fn_or_arrow_data, + &mut parameter_modifiers, + )? { with_modifiers |= 1u32 << items_list.len().min(31); } - let is_spread = p.lexer.token == T::TDotDotDot; + // `parseParenthesizedExpression`: no expression starts with the dots. + let is_spread = p.lexer.token == T::TDotDotDot + && (attempt != ArrowAttempt::NeverArrow || opts.is_async); if is_spread { spread_range = p.lexer.range(); @@ -915,7 +932,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } // We don't know yet whether these are arguments or expressions, so parse - p.latest_arrow_arg_loc = p.lexer.loc(); + // (`parseParenthesizedExpression`: a "?" after a name is the conditional operator.) + p.latest_arrow_arg_loc = if attempt == ArrowAttempt::NeverArrow { + bun_ast::Loc::EMPTY + } else { + p.lexer.loc() + }; let mut item = Expr::EMPTY; let mut has_type = false; @@ -1181,16 +1203,21 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> continue; } let mut binding = binding; - let is_typescript_ctor_field = with_modifiers & (1u32 << i.min(31)) != 0; - if is_typescript_ctor_field { - let modifiers: Vec = parameter_modifiers + let mut ts_decorators = bun_alloc::AstAlloc::vec(); + let mut is_typescript_ctor_field = false; + if with_modifiers & (1u32 << i.min(31)) != 0 { + let of_parameter = parameter_modifiers .iter() .filter(|modifier| modifier.0 == i) - .map(|modifier| modifier.1) - .collect(); - p.note_parameter_modifiers(&mut binding.loc, &modifiers); + .map(|modifier| modifier.1); + ts_decorators.extend(of_parameter.clone().filter_map(|it| it.decorator)); + let keywords: Vec = + of_parameter.filter(|it| it.decorator.is_none()).collect(); + is_typescript_ctor_field = !keywords.is_empty(); + p.note_parameter_modifiers(&mut binding.loc, &keywords); } args.push(G::Arg { + ts_decorators, binding, default: tuple.expr, is_typescript_ctor_field, @@ -1344,21 +1371,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if items.len() > 0 { p.log_expr_errors(&mut errors); if spread_range.len > 0 { - if !p.is_tolerant() || p.lexer.is_log_disabled { - p.log().add_range_error( - Some(p.source), - type_colon_range, - b"Unexpected \"...\"", - ); - return Err(crate::Error::SyntaxError); - } - // `parsePrimaryExpression`: no expression starts with the dots. - p.lexer.ts_error(spread_range, 1109); - for item in items.iter_mut() { - if let js_ast::expr::Data::ESpread(spread) = item.data { - *item = spread.value; - } - } + p.log() + .add_range_error(Some(p.source), type_colon_range, b"Unexpected \"...\""); + return Err(crate::Error::SyntaxError); } let mut value = if p.is_tolerant() { @@ -1461,15 +1476,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> fn parse_missing_parameter_name(&mut self, has_modifiers: bool) -> Result { let p = self; // `createIdentifierWithDiagnostic` - let range = p.lexer.range(); - let code = if p.lexer.token == T::TPrivateIdentifier { - 18009 - } else if p.lexer.token.is_reserved_word() || p.lexer.token == T::TEscapedKeyword { - 1359 + if p.lexer.token == T::TPrivateIdentifier { + let range = p.lexer.range(); + p.lexer.ts_error(range, 18009); } else { - 1003 - }; - p.lexer.ts_error(range, code); + p.lexer.expected(T::TIdentifier)?; + } p.latest_arrow_arg_loc = p.lexer.full_start(); let ref_ = p.store_name_in_ref(b""); let name = Expr::init_identifier(ref_, p.latest_arrow_arg_loc); @@ -1589,8 +1601,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> && !(self.lexer.identifier == b"await" && data.allow_await != AwaitOrYield::AllowIdent // TypeScript parses the statements of a file outside any [Await] context, whether - // or not await is allowed there. - && !(data.is_top_level && data.allow_await == AwaitOrYield::AllowExpr)) + // or not await is allowed there. `reparseTopLevelAwait` parses those again in it + // that have an identifier `await`. + && !(data.is_top_level + && data.allow_await == AwaitOrYield::AllowExpr + && !self.lexer.await_name_seen)) && !(self.lexer.identifier == b"yield" && data.allow_yield != AwaitOrYield::AllowIdent) } @@ -1664,6 +1679,18 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } } + // `parseClassDeclarationOrExpression` restores `statementHasAwaitIdentifier` after an + // ambient class: `reparseTopLevelAwait` parses no statement again for an `await` in one, + // which stays outside the [Await] context. + let old_await = p.fn_or_arrow_data_parse.allow_await; + if opts.is_typescript_declare + && p.is_tolerant() + && p.fn_or_arrow_data_parse.is_top_level + && !p.lexer.await_name_seen + { + p.fn_or_arrow_data_parse.allow_await = AwaitOrYield::AllowIdent; + } + // Even anonymous classes can have TypeScript type parameters if Self::IS_TYPESCRIPT_ENABLED { p.skip_class_type_parameters(&mut class_keyword.loc)?; @@ -1681,6 +1708,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> .push_scope_for_parse_pass(js_ast::scope::Kind::ClassName, loc) .expect("unreachable"); let class = p.parse_class(class_keyword, name, &class_opts)?; + p.fn_or_arrow_data_parse.allow_await = old_await; if Self::IS_TYPESCRIPT_ENABLED { if opts.is_typescript_declare { @@ -1763,12 +1791,14 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if raw == b"let" { p.lexer.next()?; - // `parseDeclarationWorker`: after modifiers "let" starts a declaration list whatever - // follows it. Only `parseStatement` asks `isLetDeclaration`. - let is_after_modifiers = p.is_tolerant() && p.statement_has_modifiers(); + // `parseDeclarationWorker`, `parseForOrForInOrForOfStatement`: after modifiers and in + // the head of a "for", "let" starts a declaration list whatever follows it. Only + // `parseStatement` asks `isLetDeclaration`. + let is_declaration = + p.is_tolerant() && (opts.is_for_loop_init || p.statement_has_modifiers()); match p.lexer.token { token - if is_after_modifiers + if is_declaration || matches!(token, T::TIdentifier | T::TOpenBracket | T::TOpenBrace) => { if opts.lexical_decl == LexicalDecl::AllowAll @@ -2308,12 +2338,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> is_computed = true; let open_bracket = p.lexer.loc(); p.lexer.next()?; - let mut expr = p.parse_expr(Level::Comma)?; - if p.lexer.token == T::TComma && p.is_tolerant() { - // `parseComputedPropertyName` accepts any expression: - // `checkGrammarComputedPropertyName` reports the comma. - p.parse_suffix(&mut expr, Level::Lowest, None, EFlags::None)?; - } + let mut expr = if p.is_tolerant() { + p.parse_expression_of_computed_name()? + } else { + p.parse_expr(Level::Comma)? + }; p.note_loc(&mut expr.loc, Mark::ComputedName, open_bracket); key = expr; p.lexer.expect(T::TCloseBracket)?; @@ -2452,6 +2481,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> return Ok(G::DeclList::from_arena_slice(&decls)); } let saved_contexts = p.enter_list(ListKind::VariableDeclarations); + // `parseVariableDeclarationList`: see `parse_expr_allow_in`. + let old_allow_in = p.allow_in; + if p.is_tolerant() { + p.allow_in = !opts.is_for_loop_init; + } loop { match p.classify_list_token(ListKind::VariableDeclarations)? { @@ -2525,6 +2559,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.next()?; } + if p.is_tolerant() { + p.allow_in = old_allow_in; + } p.lexer.list_contexts = saved_contexts; Ok(G::DeclList::from_arena_slice(&decls)) } @@ -2797,7 +2834,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> T::TStringLiteral | T::TNoSubstitutionTemplateLiteral ) .then(|| p.lexer.range().end()); - let value = p.parse_detached(|p| p.parse_expr(Level::Comma))?; + let value = p.parse_expr(Level::Comma)?; count += 1; mode = match &key { Some(key) if count == 1 => { @@ -2879,8 +2916,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let is_reparsing = eend == T::TEndOfFile && p.reparses_rest_of_file; // `parseToplevelStatement` if eend == T::TEndOfFile && !is_reparsing { - p.lexer.await_name_seen = false; + p.lexer.await_name_seen = + p.statements_with_await_in_names.contains(&p.lexer.loc()); p.await_was_refused = false; + p.await_read_as_identifier = false; } if !is_reparsing { match p.classify_list_token(list)? { @@ -2896,6 +2935,14 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let outer_modifiers_base = p.begin_statement(); let mut stmt = p.parse_stmt(&mut current_opts)?; p.end_statement(outer_modifiers_base, &mut stmt.loc); + if p.is_tolerant() + && p.await_read_as_identifier + && p.lexer.await_name_seen + && eend == T::TEndOfFile + { + p.await_read_as_identifier = false; + p.statements_with_await_in_names.push(stmt_start); + } if p.reparses_rest_of_file && eend == T::TEndOfFile && p.lexer.loc() == stmt_start { p.lexer.next()?; } @@ -3151,10 +3198,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Some(false) } else if !has_type_parameters { p.is_parenthesized_arrow_function() - } else if p.is_jsx_enabled() { - // `nextIsParenthesizedArrowFunctionExpression`, at a "<": with JSX, whatever - // `is_ts_arrow_fn_jsx` accepts is an arrow function. - Some(true) } else { None }; @@ -3262,34 +3305,31 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } } - /// The keywords of `parseModifiersEx` in `parseParameterEx`, at the first token of item number - /// `index` of the head of what is parsed as an arrow function. Adds them to `modifiers`, and - /// returns whether there are any. + /// `parseModifiersEx` in `parseParameterEx`, at the first token of item number `index` of the + /// head of what is parsed as an arrow function. Adds them to `modifiers`, and returns whether + /// there are any. `outer`: the context of the arrow function, in which decorators are parsed. #[cold] #[inline(never)] fn parse_arrow_parameter_modifiers( &mut self, index: usize, + outer: &FnOrArrowDataParse, modifiers: &mut Vec<(usize, crate::sema::ts_syntax::Modifier)>, ) -> Result { - if self.lexer.is_log_disabled || !self.is_at_modifier(false) { + if self.lexer.is_log_disabled { return Ok(false); } - let first = bun_ast::Range { - loc: self.lexer.full_start(), - len: self.lexer.range().end().start - self.lexer.full_start().start, + let mut of_parameter = Vec::new(); + let inner_is_top_level = core::mem::replace( + &mut self.fn_or_arrow_data_parse.is_top_level, + outer.is_top_level, + ); + let first = self.parse_modifiers_of_parameter(outer.allow_await, &mut of_parameter); + self.fn_or_arrow_data_parse.is_top_level = inner_is_top_level; + let Some(first) = first? else { + return Ok(false); }; - let mut has_static = false; - while self.is_at_modifier(has_static) { - has_static |= self.lexer.is_contextual_keyword(b"static"); - let modifier = crate::sema::ts_syntax::Modifier { - flag: self.modifier_flag_here(), - loc: self.lexer.loc(), - decorator: None, - }; - modifiers.push((index, modifier)); - self.lexer.next_token()?; - } + modifiers.extend(of_parameter.into_iter().map(|modifier| (index, modifier))); if self.lexer.token == T::TThis { // Neither decorators nor modifiers may be applied to "this" parameters. self.lexer.ts_error(first, 1433); @@ -3387,6 +3427,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> || p.check_for_arrow_after_the_current_token(); if is_arrow_fn { + // `tryParseAsyncSimpleArrowFunctionExpression`: the name is parsed as + // an expression. + p.new_identifier(); let ref_ = p.store_name_in_ref(p.lexer.identifier); let arg_loc = p.lexer.loc(); let arg_full_start = p.lexer.full_start(); @@ -3457,18 +3500,52 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if Self::IS_TYPESCRIPT_ENABLED && (!p.is_jsx_enabled() || p.is_ts_arrow_fn_jsx()?) { - match p - .try_skip_type_script_type_parameters_then_open_paren_with_backtracking( - )? { + let opts = ParenExprOpts { + is_async: true, + full_start: async_full_start, + is_after_question_and_before_colon: p.is_tolerant() + && flags == EFlags::AfterQuestionAndBeforeColon, + ..Default::default() + }; + // `isParenthesizedArrowFunctionExpression`: with JSX whatever + // `is_ts_arrow_fn_jsx` accepts is an arrow function. + if p.is_tolerant() + && !p.lexer.is_log_disabled + && p.is_jsx_enabled() + && level.lte(Level::Assign) + { + let opts = ParenExprOpts { + force_arrow_fn: true, + is_after_question_and_before_colon: false, + ..opts + }; + return Self::pfx_generic_arrow_fn(p, async_range.loc, level, opts); + } + // `isParenthesizedArrowFunctionExpression`: without JSX the arrow function + // is only tried. If none is there, "<" follows the name "async". + let skipped = if p.is_tolerant() + && !p.lexer.is_log_disabled + && !p.is_jsx_enabled() + && !Self::pfx_is_name_in_angle_brackets(p) + { + if level.lte(Level::Assign) + && let Some(arrow) = + p.try_parse_generic_arrow_fn(async_range.loc, level, opts)? + { + return Ok(arrow); + } + SkipTypeParameterResult::DidNotSkipAnything + } else { + p.try_skip_type_script_type_parameters_then_open_paren_with_backtracking()? + }; + match skipped { SkipTypeParameterResult::DidNotSkipAnything => {} result => { let type_parameters = p.saved_type_parameters(result); let opts = ParenExprOpts { - is_async: true, - full_start: async_full_start, force_arrow_fn: result == SkipTypeParameterResult::DefinitelyTypeParameters, - ..Default::default() + ..opts }; let mut expr = if !opts.force_arrow_fn && p.is_tolerant() diff --git a/src/js_parser/parse/parse_entry.rs b/src/js_parser/parse/parse_entry.rs index a33fa88f2da2..1a92633d76a1 100644 --- a/src/js_parser/parse/parse_entry.rs +++ b/src/js_parser/parse/parse_entry.rs @@ -391,6 +391,7 @@ impl<'a> Parser<'a> { lexer.jsc_builtin_syntax = options.jsc_builtin_syntax; lexer.tolerant = options.tolerant; lexer.is_javascript = options.is_javascript; + lexer.is_jsx = options.tolerant && options.jsx.parse; lexer.step(); lexer.next()?; // Copy the lexer's `NonNull` so both handles share one provenance @@ -485,6 +486,7 @@ impl<'a> Parser<'a> { /// deeply for the stack is marked `ran_out_of_stack`. /// `await_is_a_name`: the top level has no await context, as in a script /// (`parseSourceFileWorker`). + /// `statements`: `P::statements_with_await_in_names`, before and after. /// Also returns whether `await` was parsed as a keyword at the top level. #[cold] pub(crate) fn parse_for_sema( @@ -493,6 +495,7 @@ impl<'a> Parser<'a> { is_declaration_file: bool, is_json: bool, await_is_a_name: bool, + statements: &mut Vec, parsing: &core::cell::Cell, ) -> (bun_sema::hir::FileBuilder, bool) { type Pi<'a> = P<'a, true, false, true>; @@ -546,13 +549,7 @@ impl<'a> Parser<'a> { if await_is_a_name || is_declaration_file || is_json { p.fn_or_arrow_data_parse.allow_await = crate::AwaitOrYield::AllowIdent; } - if p.lexer.token == js_lexer::T::THashbang { - if p.lexer.next().is_err() { - return (failed(), false); - } - // `Scan`: a shebang is trivia. - p.lexer.token_full_start = 0; - } + p.statements_with_await_in_names = core::mem::take(statements); // The parser is at the first token: these are the comments `getCommentPragmas` processes. let leading_comments = p.lexer.all_comments.len(); let mut opts = ParseStatementOptions { @@ -573,12 +570,12 @@ impl<'a> Parser<'a> { p.parse_stmts_up_to(js_lexer::T::TEndOfFile, &mut opts) }; parsing.set(parsing.get() + began.elapsed()); + *statements = core::mem::take(&mut p.statements_with_await_in_names); let awaited = p.top_level_await_keyword.len > 0; // Taken before `jsdoc::read_comments` makes the lexer rescan the comments. let comment_directives = core::mem::take(&mut p.lexer.comment_directives); // Recoverable errors are converted to TypeScript's diagnostics. The checker reports them. let mut logged = Vec::new(); - let has_jsx = p.is_jsx_enabled(); let mut has_errors = stmts.is_err(); // The offset of the first error that has no TypeScript equivalent. let mut untranslated = None; @@ -591,14 +588,7 @@ impl<'a> Parser<'a> { bstr::BStr::new(&msg.data.text) ); let source = self.source.contents(); - match crate::sema::diagnostic(msg, source, has_jsx) { - // `checkJSDecoratorSyntax` reports these two as JS diagnostics, which parse errors do not suppress. - Some(Some(diagnostic)) if is_js && matches!(diagnostic.code, 1206 | 8038) => { - logged.push(Diagnostic { - kind: DiagnosticKind::Js, - ..diagnostic - }); - } + match crate::sema::diagnostic(msg, source) { Some(diagnostic) => logged.extend(diagnostic), None => { has_errors = true; diff --git a/src/js_parser/parse/parse_fn.rs b/src/js_parser/parse/parse_fn.rs index 5fce8919cadd..46439b6a3e7e 100644 --- a/src/js_parser/parse/parse_fn.rs +++ b/src/js_parser/parse/parse_fn.rs @@ -305,7 +305,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> )?; } // Skip over "this" type annotations - if Self::IS_TYPESCRIPT_ENABLED && p.lexer.token == T::TThis { + if Self::IS_TYPESCRIPT_ENABLED + && (p.lexer.token == T::TThis || (takes_any_modifiers && p.token() == T::TThis)) + { if takes_any_modifiers { let is_first = args.is_empty() && !has_this_parameter; has_this_parameter = true; @@ -377,10 +379,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut ts_metadata = bun_ast::ts::Metadata::default(); // `parseNameOfParameter`: a modifier keyword that is neither a modifier nor a name is skipped. - if matches!(p.lexer.token, T::TConst | T::TDefault | T::TExport | T::TIn) - && p.is_tolerant() + if p.is_tolerant() && modifiers.is_none() && p.lexer.loc() == name_start + && p.is_modifier_kind() { p.lexer.next()?; } @@ -556,6 +558,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } let mut temp_opts = opts; func.body = p.parse_fn_body(&mut temp_opts)?; + let open_parens = p.real_loc(func.open_parens_loc); + p.note_function_context(open_parens, temp_opts.allow_await, temp_opts.allow_yield); if p.lexer.has_react_hooks_suppression_before || p.lexer.has_react_hooks_block_suppression { func.flags.insert(Flags::Function::HasReactHooksSuppression); // next-line semantics: a suppression marks the enclosing top-level @@ -643,22 +647,22 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> /// it. fn next_token_can_follow_modifier(&mut self) -> bool { let p = self; - let keyword = p.lexer.token; + let keyword = p.token(); let mut is_after_default = keyword == T::TDefault; let is_static = p.lexer.is_contextual_keyword(b"static"); - if p.lexer.next().is_err() { + if !p.step() { return false; } match keyword { T::TConst => return p.lexer.token == T::TEnum, T::TExport if p.lexer.token == T::TDefault => { is_after_default = true; - if p.lexer.next().is_err() { + if !p.step() { return false; } } T::TExport => { - if p.lexer.is_contextual_keyword(b"type") && p.lexer.next().is_err() { + if p.lexer.is_contextual_keyword(b"type") && !p.step() { return false; } // `canFollowExportModifier` @@ -685,9 +689,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> }, _ => return false, }; - return p.lexer.next().is_ok() - && p.lexer.token == expected - && !p.lexer.has_newline_before; + return p.step() && p.lexer.token == expected && !p.lexer.has_newline_before; } // `canFollowModifier`. Only "static" and "export" may be followed by a line break. (is_static || keyword == T::TExport || !p.lexer.has_newline_before) @@ -872,7 +874,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let old_fn_or_arrow_data = p.fn_or_arrow_data_parse.clone(); let old_allow_in = p.allow_in; p.fn_or_arrow_data_parse = data.clone(); - p.allow_in = true; + // `parseFunctionBlock` leaves the context as it is: see `parse_expr_allow_in`. + p.allow_in = old_allow_in || !p.is_tolerant(); let loc = p.lexer.loc(); let mut pushed_scope_for_function_body = false; @@ -973,6 +976,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.parse_fn_body(data)? }; p.note_loc(&mut body.loc, Mark::ArrowToken, arrow_token); + p.note_function_context(arrow_loc, data.allow_await, data.allow_yield); p.after_arrow_body_loc = p.lexer.loc(); let has_react_hooks_suppression = p.lexer.has_react_hooks_suppression_before || p.lexer.has_react_hooks_block_suppression; @@ -1020,6 +1024,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } }; p.fn_or_arrow_data_parse = old_fn_or_arrow_data; + p.note_function_context(arrow_loc, data.allow_await, data.allow_yield); let ret_stmt = p.s(S::Return { value: Some(expr) }, expr.loc); let stmts: &'a mut [Stmt] = p.arena.alloc_slice_copy(&[ret_stmt]); @@ -1057,7 +1062,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[inline(never)] fn is_arrow_body_missing_open_brace(&mut self) -> bool { !matches!( - self.lexer.token, + self.token(), T::TSemicolon | T::TFunction | T::TClass | T::TOpenBrace ) && self.is_start_of_statement() // `isStartOfExpressionStatement` @@ -1074,9 +1079,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> ) -> Result { let p = self; let old_fn_or_arrow_data = p.fn_or_arrow_data_parse.clone(); - let old_allow_in = p.allow_in; p.fn_or_arrow_data_parse = data.clone(); - p.allow_in = true; let loc = p.lexer.loc(); let _ = p.push_scope_for_parse_pass(js_ast::scope::Kind::FunctionBody, loc)?; @@ -1086,7 +1089,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.end_of_block(loc)?; p.pop_scope(); - p.allow_in = old_allow_in; p.fn_or_arrow_data_parse = old_fn_or_arrow_data; Ok(G::FnBody { loc, diff --git a/src/js_parser/parse/parse_import_export.rs b/src/js_parser/parse/parse_import_export.rs index d7608bec2621..fd504541ccda 100644 --- a/src/js_parser/parse/parse_import_export.rs +++ b/src/js_parser/parse/parse_import_export.rs @@ -159,15 +159,38 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } /// The type arguments just parsed, which are those of an import call. - /// `checkImportCallExpression` never checks them, so the errors the list logged about itself - /// (1099, 1009) are removed: the log had `logged` messages and `errors` errors before it. + /// `checkImportCallExpression` never checks them, so the checker's errors that were logged for + /// them (1099, 1009) are removed: the log had `logged` messages and `errors` errors before it. fn type_arguments_of_import_call(&mut self, logged: usize, errors: u32) -> Option { let log = self.log(); - log.msgs.truncate(logged); - log.errors = errors; + let of_parser: Vec = (log.msgs.drain(logged..)) + .filter(crate::sema::is_parse_error) + .collect(); + log.errors = errors + of_parser.len() as u32; + log.msgs.extend(of_parser); self.saved_type_arguments() } + /// The `import` just parsed is an element of a heritage clause, which + /// `checkExpressionWithTypeArguments` never sees. Removes the 1326 logged for it since the log + /// had `logged` messages, and returns whether there was one: `checkGrammarHeritageClause` + /// decides. + pub(crate) fn take_back_import_with_type_arguments(&mut self, logged: usize) -> bool { + let log = self.log(); + let is_logged = log.msgs.len() > logged + && log.msgs.last().is_some_and(|msg| { + matches!( + msg.metadata, + bun_ast::Metadata::TypeScript { code: 1326, .. } + ) + }); + if is_logged { + log.msgs.pop(); + log.errors -= 1; + } + is_logged + } + /// `import.name` where the name is not `meta`, after the dot /// (`parseLeftHandSideExpressionOrHigher`). It is a meta property of the error type whatever /// the name is, and `checkGrammarMetaProperty` reports it. It is represented as a property @@ -181,7 +204,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> type_arguments: &mut Option, ) -> Result, Error> { let p = self; - if !p.lexer.is_identifier_or_keyword() { + let is_private_name = p.lexer.token == T::TPrivateIdentifier; + if !p.lexer.is_identifier_or_keyword() && !is_private_name { // `parseIdentifierName`: 1003, nothing consumed. p.lexer.expect(T::TIdentifier)?; return Ok(Some(p.new_expr(E::Missing {}, loc))); @@ -205,15 +229,32 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } return Ok(None); } - let is_callee = p.lexer.token == T::TOpenParen - || (!has_type_arguments - && p.lexer.token == T::TQuestionDot - && p.next_token_matches(|p| { - matches!( - p.lexer.token, - T::TOpenParen | T::TLessThan | T::TLessThanLessThan - ) - })); + let is_optional_callee = !has_type_arguments + && p.lexer.token == T::TQuestionDot + && p.next_token_matches(|p| { + matches!( + p.lexer.token, + T::TOpenParen | T::TLessThan | T::TLessThanLessThan + ) + }); + // `IsImportCall` does not look at the `?.`. + if is_defer && is_optional_callee { + let question_dot = p.lexer.snapshot(); + p.lexer.next()?; + if p.lexer.token == T::TOpenParen { + return Ok(None); + } + // `parseCallExpressionRest`: with type arguments it is a call whatever follows them. + if TYPESCRIPT + && !p.lexer.is_javascript_file() + && p.try_skip_type_script_type_arguments_with_backtracking()? + { + *type_arguments = p.type_arguments_of_import_call(logged, errors); + return Ok(None); + } + p.lexer.restore(&question_dot); + } + let is_callee = p.lexer.token == T::TOpenParen || is_optional_callee; if is_defer { if !is_callee { // "(" expected, at the end of the meta property. @@ -229,17 +270,23 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let named = [word, b"import", b"meta"].join(&0); p.lexer.ts_grammar_error_about(name, 17012, &named); } - let target = p.new_expr(E::Missing {}, loc); - let mut property = p.new_expr_ending_at( - E::Dot { - target, - name: text, - name_loc: name.loc, - ..Default::default() - }, - loc, - name.end(), - ); + let mut property = if is_private_name { + // `parseIdentifierName` makes an `Identifier` of it. A property access would look it + // up as the private name of a class. + p.new_expr_ending_at(E::Missing {}, loc, name.end()) + } else { + let target = p.new_expr(E::Missing {}, loc); + p.new_expr_ending_at( + E::Dot { + target, + name: text, + name_loc: name.loc, + ..Default::default() + }, + loc, + name.end(), + ) + }; if has_type_arguments { p.note_type_arguments(&mut property, less_than); } diff --git a/src/js_parser/parse/parse_jsx.rs b/src/js_parser/parse/parse_jsx.rs index 4fdf44df9f7a..65cf0bfbf98c 100644 --- a/src/js_parser/parse/parse_jsx.rs +++ b/src/js_parser/parse/parse_jsx.rs @@ -41,9 +41,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut type_arguments = crate::sema::ts_syntax::Types::EMPTY; if TYPESCRIPT { // Pass a flag to the type argument skipper because we need to call - // `()? { @@ -739,9 +739,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.put_up_with(before)?; return Ok(false); } - if p.lexer.is_less_than_slash() { - p.lexer.step(); - } p.lexer.next_inside_jsx_element()?; Ok(true) } diff --git a/src/js_parser/parse/parse_prefix.rs b/src/js_parser/parse/parse_prefix.rs index 5effd9cc7f0c..0f0b75cc3ff1 100644 --- a/src/js_parser/parse/parse_prefix.rs +++ b/src/js_parser/parse/parse_prefix.rs @@ -256,6 +256,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } (p.lexer.range(), p.lexer.raw()) }; + let escaped_word = if p.is_tolerant() && async_kind != AsyncPrefixExpression::None { + p.lexer.escaped_word() + } else { + None + }; p.lexer.next()?; @@ -268,14 +273,21 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> return p.parse_async_prefix_expr(name_range, full_start, level, flags); } if p.is_tolerant() && !p.lexer.is_log_disabled { - return Self::pfx_escaped_async(p, name_range, full_start, level, flags); + return Self::pfx_escaped_async( + p, + name_range, + escaped_word, + full_start, + level, + flags, + ); } } AsyncPrefixExpression::IsAwait => match p.fn_or_arrow_data_parse.allow_await { // `parseParametersWorker`, `parseClassStaticBlockBody`: an await context. AwaitOrYield::ForbidAll if p.is_tolerant() && level.lte(Level::Prefix) => { - return Self::pfx_misplaced_await(p, name_range, raw, level); + return Self::pfx_misplaced_await(p, name_range, escaped_word, level); } AwaitOrYield::ForbidAll => { p.log().add_range_error( @@ -294,10 +306,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> b"The keyword \"await\" cannot be escaped", ); } else { - if is_escaped { - // `nextToken`: it is the keyword it spells, and the escape is reported. - p.lexer.ts_error(name_range, 1260); - } + p.lexer.keyword_was_taken(escaped_word); if p.fn_or_arrow_data_parse.is_top_level { p.top_level_await_keyword = name_range; @@ -327,8 +336,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> && level.lte(Level::Prefix) && Self::pfx_operand_follows_on_same_line(p) { - return Self::pfx_misplaced_await(p, name_range, raw, level); + return Self::pfx_misplaced_await(p, name_range, escaped_word, level); } + // Outside the await context of the top level of a module: a computed name, or the + // initializer of a field, which stays outside it. + p.await_read_as_identifier |= + p.is_tolerant() && p.fn_or_arrow_data_parse.is_top_level; p.lexer.prev_token_was_await_keyword = !p.is_tolerant(); p.lexer.fn_or_arrow_start_loc = p.fn_or_arrow_data_parse.needs_async_loc; // `isUpdateExpression`: `await` does not start one even where it is an @@ -346,7 +359,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> match p.fn_or_arrow_data_parse.allow_yield { // `parseParametersWorker`: a yield context. AwaitOrYield::ForbidAll if p.is_tolerant() && level.lte(Level::Assign) => { - return Self::pfx_misplaced_yield(p, name_range, raw, true); + return Self::pfx_misplaced_yield(p, name_range, escaped_word, true); } AwaitOrYield::ForbidAll => { p.log().add_range_error( @@ -365,11 +378,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> b"The keyword \"yield\" cannot be escaped", ); } else { - if is_escaped { - // `nextToken`: it is the keyword it spells, and the escape is - // reported. - p.lexer.ts_error(name_range, 1260); - } + p.lexer.keyword_was_taken(escaped_word); if level.gt(Level::Assign) { p.log().add_range_error( @@ -396,7 +405,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> && level.lte(Level::Assign) && Self::pfx_operand_follows_on_same_line(p) { - return Self::pfx_misplaced_yield(p, name_range, raw, false); + return Self::pfx_misplaced_yield(p, name_range, escaped_word, false); } // Try to gracefully recover if "yield" is used in the wrong place if !p.lexer.has_newline_before { @@ -483,13 +492,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> fn pfx_misplaced_await( p: &mut Self, await_range: bun_ast::Range, - raw: &[u8], + escaped_word: Option, level: Level, ) -> PResult { - if AsyncPrefixExpression::find(raw) != AsyncPrefixExpression::IsAwait { - // `nextToken`: a keyword that contains an escape. - p.lexer.ts_error(await_range, 1260); - } + p.lexer.keyword_was_taken(escaped_word); let value = p.parse_expr(Level::Prefix)?; if p.lexer.token == T::TAsteriskAsterisk { p.unary_before_exponentiation(level, await_range.loc, b"await")?; @@ -504,13 +510,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> fn pfx_misplaced_yield( p: &mut Self, yield_range: bun_ast::Range, - raw: &[u8], + escaped_word: Option, in_generator: bool, ) -> PResult { - if AsyncPrefixExpression::find(raw) != AsyncPrefixExpression::IsYield { - // `nextToken`: a keyword that contains an escape. - p.lexer.ts_error(yield_range, 1260); - } + p.lexer.keyword_was_taken(escaped_word); if !in_generator && !p.lexer.is_log_disabled { p.log().add_range_error( Some(p.source), @@ -875,12 +878,24 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> fn pfx_t_at(p: &mut Self) -> PResult { // Parse decorators before a class expression: @dec class { ... } let at_loc = p.lexer.loc(); - let ts_decorators = p.parse_type_script_decorators()?; + // `parseDecoratedExpression`: `parseModifiersEx`, which takes keywords too. + // `checkGrammarModifiers` reports them. + let mut modifiers = Vec::new(); + let ts_decorators = if p.is_tolerant() { + let allow_await = p.fn_or_arrow_data_parse.allow_await; + p.parse_modifiers_of_parameter(allow_await, &mut modifiers)?; + let mut decorators = bun_alloc::AstAlloc::vec(); + decorators.extend(modifiers.iter().filter_map(|modifier| modifier.decorator)); + modifiers.retain(|modifier| modifier.decorator.is_none()); + decorators + } else { + p.parse_type_script_decorators()? + }; // Expect class keyword after decorators if p.lexer.token != T::TClass { if p.is_tolerant() && !p.lexer.is_log_disabled { - // `parseDecoratedExpression`: 1109 at the end of the last decorator, and a missing + // `parseDecoratedExpression`: 1109 at the end of the last modifier, and a missing // declaration. let node_pos = p.lexer.full_start(); p.note_stray_decorators(ts_decorators.slice(), node_pos); @@ -900,6 +915,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let loc = p.lexer.loc(); let full_start = p.pos_for_jsdoc(); let mut class_keyword = p.lexer.range(); + p.note_parameter_modifiers(&mut class_keyword.loc, &modifiers); p.lexer.next()?; let mut name: Option = None; @@ -1083,9 +1099,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut self_errors = DeferredErrors::default(); let mut comma_after_spread = bun_ast::Loc::default(); - // Allow "in" inside arrays + // Allow "in" inside arrays. (`parseArrayLiteralExpression` leaves the context as it is: see + // `parse_expr_allow_in`.) let old_allow_in = p.allow_in; - p.allow_in = true; + p.allow_in = old_allow_in || !p.is_tolerant(); let saved_contexts = p.enter_list(ListKind::ArrayLiteralMembers); while p.lexer.token != T::TCloseBracket { @@ -1228,9 +1245,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut self_errors = DeferredErrors::default(); let mut comma_after_spread: bun_ast::Loc = bun_ast::Loc::default(); - // Allow "in" inside object literals + // Allow "in" inside object literals. (`parseObjectLiteralElement` does so for the value of a + // property only: see `parse_expr_allow_in`.) let old_allow_in = p.allow_in; - p.allow_in = true; + p.allow_in = old_allow_in || !p.is_tolerant(); let saved_contexts = p.enter_list(ListKind::ObjectLiteralMembers); while p.lexer.token != T::TCloseBrace { @@ -1380,22 +1398,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // (x) => {} if Self::IS_TYPESCRIPT_ENABLED && p.is_jsx_enabled() { if p.is_ts_arrow_fn_jsx()? { - let type_parameters = - p.parse_type_parameters(TypeParameterFlag::ALLOW_CONST_MODIFIER)?; - p.lexer.expect(T::TOpenParen)?; - let mut value = p.parse_paren_expr( - loc, - level, - ParenExprOpts { - force_arrow_fn: true, - full_start, - ..Default::default() - }, - )?; - if matches!(value.data, ExprData::EArrow(_)) { - p.note_type_parameters(&mut value.loc, type_parameters); - } - return Ok(value); + let opts = ParenExprOpts { + force_arrow_fn: true, + full_start, + ..Default::default() + }; + return Self::pfx_generic_arrow_fn(p, loc, level, opts); } } @@ -1453,6 +1461,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> ParenExprOpts { force_arrow_fn: result == SkipTypeParameterResult::DefinitelyTypeParameters, + is_after_question_and_before_colon: p.is_tolerant() + && flags == EFlags::AfterQuestionAndBeforeColon, open_paren, full_start, ..Default::default() @@ -1512,11 +1522,33 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Err(crate::Error::SyntaxError) } + /// `parseParenthesizedArrowFunctionExpression` with `allowAmbiguity`, at the `<` of its type + /// parameters. `loc`: of its first token. + pub(super) fn pfx_generic_arrow_fn( + p: &mut Self, + loc: bun_ast::Loc, + level: Level, + opts: ParenExprOpts, + ) -> PResult { + let type_parameters = p.parse_type_parameters(TypeParameterFlag::ALLOW_CONST_MODIFIER)?; + let mut value = + if p.lexer.token != T::TOpenParen && p.is_tolerant() && !p.lexer.is_log_disabled { + Self::pfx_arrow_without_parameters(p, loc, opts.full_start, opts.is_async)? + } else { + p.lexer.expect(T::TOpenParen)?; + p.parse_paren_expr(loc, level, opts)? + }; + if matches!(value.data, ExprData::EArrow(_)) { + p.note_type_parameters(&mut value.loc, type_parameters); + } + Ok(value) + } + /// Whether the `<` the lexer is at opens ``, which is the same tokens as the type parameters /// of an arrow function and as the type of a type assertion: it need not be parsed twice. #[cold] #[inline(never)] - fn pfx_is_name_in_angle_brackets(p: &mut Self) -> bool { + pub(super) fn pfx_is_name_in_angle_brackets(p: &mut Self) -> bool { p.look_ahead(|p| { p.step() && p.is_identifier_in_context() && p.step() && p.lexer.token == T::TGreaterThan }) @@ -1529,7 +1561,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // The operand of a unary operator is parsed at Level::Prefix: no lookahead, and `mustBeUnary`. let must_be_unary = level.eql(Level::Prefix); let starts_jsx = level.lte(Level::Prefix) - && !p.lexer.is_less_than_slash() && (must_be_unary // `nextTokenIsIdentifierOrKeywordOrGreaterThan` || p.next_token_matches(|p| { @@ -1578,7 +1609,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if p.lexer.token == T::TGreaterThan { p.lexer.next()?; } - if must_be_unary || p.lexer.token != T::TLessThan || p.lexer.is_less_than_slash() { + if must_be_unary || p.lexer.token != T::TLessThan { return Ok(element); } if p.lexer.is_log_disabled { @@ -1657,6 +1688,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> fn pfx_escaped_async( p: &mut Self, async_range: bun_ast::Range, + escaped_word: Option, async_full_start: bun_ast::Loc, level: Level, flags: EFlags, @@ -1668,7 +1700,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> _ => false, }; if is_modifier { - p.lexer.ts_error(async_range, 1260); + p.lexer.keyword_was_taken(escaped_word); } Ok(expr) } @@ -1709,22 +1741,49 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.is_tolerant() && !p.next_token_matches(|p| p.lexer.is_identifier_or_keyword()) } - /// `isParenthesizedArrowFunctionExpression`: a lone `=>` where an assignment expression starts - /// is treated as an arrow function. `parseParenthesizedArrowFunctionExpression`: 1005 for the - /// `(`, and there are no parameters. + /// `parseParenthesizedArrowFunctionExpression` with `allowAmbiguity`, at a token other than its + /// `(`: 1005, and there are no parameters. `isParenthesizedArrowFunctionExpression`: so for a + /// lone `=>` where an assignment expression starts. `loc`, `full_start`: of its first token. #[cold] #[inline(never)] - fn pfx_arrow_without_parameters(p: &mut Self) -> PResult { - let loc = p.lexer.loc(); + fn pfx_arrow_without_parameters( + p: &mut Self, + loc: bun_ast::Loc, + full_start: bun_ast::Loc, + is_async: bool, + ) -> PResult { p.lexer.expect(T::TOpenParen)?; let _ = p.push_scope_for_parse_pass(scope::Kind::FunctionArgs, loc)?; + let mut return_type = crate::sema::ts_syntax::TypeId::NONE; + if p.lexer.token == T::TColon { + p.lexer.next()?; + p.skip_typescript_return_type()?; + return_type = p.saved_type_or_error(); + } let mut fn_or_arrow_data = FnOrArrowDataParse { needs_async_loc: loc, + allow_await: if is_async { + AwaitOrYield::AllowExpr + } else { + AwaitOrYield::AllowIdent + }, ..Default::default() }; + let has_arrow_token = p.lexer.token == T::TEqualsGreaterThan; let arrow_result = p.parse_arrow_body(&mut [], &mut fn_or_arrow_data); p.pop_scope(); - Ok(p.new_expr(arrow_result?, loc)) + let mut arrow = arrow_result?; + arrow.is_async = is_async; + if !has_arrow_token && arrow.prefer_expr && p.lexer.token != T::TComma { + // `parseAssignmentExpressionOrHigher` returns the arrow function as is. + p.forbid_suffix_after_as_loc = p.lexer.loc(); + } + let mut arrow = p.new_expr(arrow, loc); + p.mark_comments_before(&mut arrow.loc, loc, full_start); + if return_type.is_some() { + p.note_saved_type(&mut arrow.loc, crate::sema::Mark::ReturnType, return_type); + } + Ok(arrow) } /// `parseUnaryExpressionOrHigher`: the expression that starts at `loc` is the left operand of @@ -1805,7 +1864,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> && p.is_tolerant() && !p.lexer.is_log_disabled { - return Self::pfx_arrow_without_parameters(p); + let (loc, full_start) = (p.lexer.loc(), p.pos_for_jsdoc()); + return Self::pfx_arrow_without_parameters(p, loc, full_start, false); } if p.lexer.token == T::TEndOfFile && p.is_tolerant() && !p.lexer.is_log_disabled { return Self::pfx_missing_at_end_of_file(p); diff --git a/src/js_parser/parse/parse_property.rs b/src/js_parser/parse/parse_property.rs index 8c04868da693..dd42568e50c5 100644 --- a/src/js_parser/parse/parse_property.rs +++ b/src/js_parser/parse/parse_property.rs @@ -271,7 +271,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let old_yield = self.fn_or_arrow_data_parse.allow_yield; self.fn_or_arrow_data_parse.allow_await = AwaitOrYield::AllowIdent; self.fn_or_arrow_data_parse.allow_yield = AwaitOrYield::AllowIdent; - let initializer = self.parse_expr(Level::Comma); + let initializer = self.parse_expr_allow_in(Level::Comma); self.fn_or_arrow_data_parse.allow_await = old_await; self.fn_or_arrow_data_parse.allow_yield = old_yield; initializer @@ -280,15 +280,20 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> /// `parseComputedPropertyName`, between the brackets: any expression. /// `checkGrammarComputedPropertyName` reports a comma. `parsePropertyName` restores /// `statementHasAwaitIdentifier`, so `reparseTopLevelAwait` parses no statement again for an - /// `await` in a name: at the top level it is read outside the await context. + /// `await` in a name: at the top level it is read outside the await context, unless the + /// statement is parsed again for another `await`. One that comes after the name is only known + /// at the end of the statement (`statements_with_await_in_names`). #[cold] #[inline(never)] - fn parse_expression_of_computed_name(&mut self) -> crate::CrateResult { + pub(crate) fn parse_expression_of_computed_name(&mut self) -> crate::CrateResult { let old_await = self.fn_or_arrow_data_parse.allow_await; - if self.fn_or_arrow_data_parse.is_top_level && old_await == AwaitOrYield::AllowExpr { + if self.fn_or_arrow_data_parse.is_top_level + && old_await == AwaitOrYield::AllowExpr + && !self.lexer.await_name_seen + { self.fn_or_arrow_data_parse.allow_await = AwaitOrYield::AllowIdent; } - let expression = self.parse_expr(Level::Lowest); + let expression = self.parse_expr_allow_in(Level::Lowest); self.fn_or_arrow_data_parse.allow_await = old_await; expression } @@ -306,7 +311,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut kind = kind_; let mut errors = errors_; // `Lexer::escaped_word` of the word consumed last, until it is known to be a name. - let mut escaped_word: Option = None; + let mut escaped_word: Option = None; // This while loop exists to conserve stack space by reducing (but not completely eliminating) recursion. 'restart: loop { p.lexer.keyword_was_taken(escaped_word.take()); @@ -686,6 +691,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.pop_scope(); p.fn_or_arrow_data_parse = old_fn_or_arrow_data_parse; + p.note_function_context( + loc, + AwaitOrYield::ForbidAll, + AwaitOrYield::AllowIdent, + ); // `parseClassStaticBlockBody` is `parseBlock`. p.lexer.expect_closing(T::TCloseBrace, loc)?; @@ -825,7 +835,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if p.lexer.token == T::TEquals { errors.invalid_expr_default_value = Some(p.lexer.range()); p.lexer.next()?; - initializer = Some(p.parse_expr(Level::Comma)?); + initializer = Some(p.parse_expr_allow_in(Level::Comma)?); } } @@ -1094,12 +1104,20 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> ..Default::default() }; + // See `parse_expr_allow_in`. + let old_allow_in = p.allow_in; + if p.is_tolerant() { + p.allow_in = true; + } // `errors` is Option<&mut _>; reborrow via as_deref_mut so the caller's binding stays usable p.parse_expr_or_bindings( Level::Comma, errors.as_deref_mut(), property.value.as_mut().unwrap(), )?; + if p.is_tolerant() { + p.allow_in = old_allow_in; + } return Ok(Some(property)); } } @@ -1112,11 +1130,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> fn is_uncommon_modifier(&mut self, word: &[u8], is_class: bool) -> bool { match word { // Without `permitConstAsModifier`, only before `enum`. - b"const" if !is_class => self.lexer.token == T::TEnum, + b"const" if !is_class => self.token() == T::TEnum, b"const" | b"in" | b"out" => !self.lexer.has_newline_before, b"default" => self.can_follow_default_keyword(), b"export" => { - let is_default = self.lexer.token == T::TDefault; + let is_default = self.token() == T::TDefault; if !is_default && !self.lexer.is_contextual_keyword(b"type") { return self.can_follow_export_modifier(); } @@ -1151,7 +1169,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> /// `nextTokenCanFollowDefaultKeyword`, on the token after `default`. fn can_follow_default_keyword(&mut self) -> bool { - let expected = match self.lexer.token { + let expected = match self.token() { T::TClass | T::TFunction | T::TAt => return true, T::TIdentifier => match self.lexer.identifier { b"interface" => return true, @@ -1161,13 +1179,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> }, _ => return false, }; - let here = self.lexer.snapshot(); - self.lexer.is_log_disabled = true; - let found = self.lexer.next().is_ok() - && self.lexer.token == expected - && !self.lexer.has_newline_before; - self.lexer.restore(&here); - found + self.look_ahead(|p| p.step() && p.lexer.token == expected && !p.lexer.has_newline_before) } /// Whether `word` is a modifier of a member before the `{` or `...` the lexer is at. `canFollowModifier` accepts both, diff --git a/src/js_parser/parse/parse_skip_typescript.rs b/src/js_parser/parse/parse_skip_typescript.rs index 1ceb49b5f82c..288086224b23 100644 --- a/src/js_parser/parse/parse_skip_typescript.rs +++ b/src/js_parser/parse/parse_skip_typescript.rs @@ -167,7 +167,13 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.lexer.next()?; } // "[a, b]" + let old_allow_in = self.allow_in; + self.allow_in |= self.is_tolerant(); + let saved_contexts = self.enter_list(ListKind::ArrayBindingElements); while self.lexer.token != T::TCloseBracket { + if !self.skip_to_list_element(ListKind::ArrayBindingElements)? { + break; + } // "[a, , b]": `parseArrayBindingElement` produces an omitted element wherever a // comma appears. if self.lexer.token == T::TComma && self.is_tolerant() { @@ -207,6 +213,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } if self.lexer.token != T::TComma { + if self.recover_missing_comma(ListKind::ArrayBindingElements, loc)? { + continue; + } break; } if is_rest && self.is_tolerant() { @@ -214,6 +223,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } self.lexer.next()?; } + self.lexer.list_contexts = saved_contexts; + self.allow_in = old_allow_in; self.lexer.expect(T::TCloseBracket)?; if keeps { @@ -224,7 +235,13 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.lexer.next()?; let mut properties: Vec = Vec::new(); + let old_allow_in = self.allow_in; + self.allow_in |= self.is_tolerant(); + let saved_contexts = self.enter_list(ListKind::ObjectBindingElements); while self.lexer.token != T::TCloseBrace { + if !self.skip_to_list_element(ListKind::ObjectBindingElements)? { + break; + } let mut found_identifier = false; let loc = self.lexer.loc(); // "{...x: y}": `parseObjectBindingElement` parses what follows the dots like @@ -272,8 +289,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.lexer.next()?; } - // "{1n: y}": `isLiteralPropertyName` - T::TBigIntegerLiteral if self.lexer.tolerant => { + // "{1n: y}", "{#x: y}": `parsePropertyName` + T::TBigIntegerLiteral | T::TPrivateIdentifier if self.lexer.tolerant => { self.lexer.next()?; } @@ -287,6 +304,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if self.lexer.is_identifier_or_keyword() { // "{if: x}" self.lexer.next()?; + } else if self.lexer.tolerant { + // `parseIdentifierName`: the name is missing, and the token is not + // consumed. + self.lexer.expect(T::TIdentifier)?; } else { self.lexer.unexpected()?; } @@ -317,6 +338,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } if self.lexer.token != T::TComma { + if self.recover_missing_comma(ListKind::ObjectBindingElements, loc)? { + continue; + } break; } if is_rest { @@ -325,13 +349,15 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.lexer.next()?; } + self.lexer.list_contexts = saved_contexts; + self.allow_in = old_allow_in; self.lexer.expect(T::TCloseBrace)?; if keeps { self.emit_object_binding(&properties, pos); } } - _ if self.starts_no_binding_name() => self.skip_missing_binding_name(true)?, + _ if self.is_tolerant() => self.skip_missing_binding_identifier()?, _ => { self.lexer.unexpected()?; return Err(crate::Error::SyntaxError); @@ -340,11 +366,41 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(()) } - /// Whether `skip_missing_binding_name` applies: no identifier or pattern starts here. A speculative parse must still fail. + /// `parseBindingIdentifier` in a pattern of a type-level signature, where no identifier starts + /// (`createIdentifierWithDiagnostic`). + #[cold] + #[inline(never)] + fn skip_missing_binding_identifier(&mut self) -> Result<(), Error> { + let keeps = self.should_save_types(); + if self.lexer.token == T::TPrivateIdentifier { + if keeps { + self.emit_identifier_binding(); + } + return self.skip_private_identifier_as_name(); + } + // `createMissingIdentifier`: at the end of the previous token. The token is not consumed. + let loc = self.lexer.full_start(); + self.lexer.expect(T::TIdentifier)?; + if keeps { + self.emit_missing_binding(loc); + } + Ok(()) + } + + /// `createIdentifierWithDiagnostic` at a private identifier: it is reported, and used as the + /// name. + #[cold] + #[inline(never)] + fn skip_private_identifier_as_name(&mut self) -> Result<(), Error> { + let range = self.lexer.range(); + self.lexer.ts_error(range, 18016); + Ok(self.lexer.next()?) + } + + /// Whether `skip_missing_binding_name` applies: no identifier or pattern starts here. #[inline] fn starts_no_binding_name(&self) -> bool { self.is_tolerant() - && !self.lexer.is_log_disabled && !matches!( self.lexer.token, T::TIdentifier | T::TOpenBracket | T::TOpenBrace @@ -382,16 +438,20 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> fn skip_typescript_fn_args_after_open_paren(&mut self) -> Result<(), Error> { if !self.is_tolerant() { - return self.skip_typescript_fn_args_in_context(); + return self.skip_typescript_fn_args_in_context(crate::AwaitOrYield::AllowIdent); } // `parseParametersWorker(ParseFlagsType)` let outer = self.replace_await_and_yield([crate::AwaitOrYield::AllowIdent; 2]); - let skipped = self.skip_typescript_fn_args_in_context(); + let skipped = self.skip_typescript_fn_args_in_context(outer[0]); self.replace_await_and_yield(outer); skipped } - fn skip_typescript_fn_args_in_context(&mut self) -> Result<(), Error> { + /// `outer_await`: the [Await] context around the signature (`inAwaitContext`). + fn skip_typescript_fn_args_in_context( + &mut self, + outer_await: crate::AwaitOrYield, + ) -> Result<(), Error> { // Keep mode stores the result in `TypeSyntax::last_params`. let keeps = self.should_save_types(); let mut parameters: Vec = Vec::new(); @@ -410,11 +470,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // the checker reports them. let mut first_modifier = None; if self.is_tolerant() && (self.lexer.token == T::TAt || self.is_modifier_kind()) { - first_modifier = self.skip_parameter_modifiers(&mut parameter)?; + first_modifier = self.skip_parameter_modifiers(&mut parameter, outer_await)?; } let has_modifiers = first_modifier.is_some(); // "(this: any)": `parseParameterEx` parses the name and a type annotation, no more. - let is_this = self.lexer.token == T::TThis && self.is_tolerant(); + let is_this = self.is_tolerant() && self.token() == T::TThis; // "(...a)" if self.lexer.token == T::TDotDotDot { parameter.rest_loc = self.lexer.loc(); @@ -490,13 +550,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[cold] #[inline(never)] pub(crate) fn is_unambiguously_index_signature(&mut self) -> bool { - let (here, swallowed) = (self.lexer.snapshot(), self.lexer.swallowed); + let here = self.lexer.snapshot(); self.lexer.is_log_disabled = true; let found = self .next_is_unambiguously_index_signature() .unwrap_or(false); self.lexer.restore(&here); - self.lexer.swallowed = swallowed; found } @@ -554,9 +613,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> parameter.full_start = self.lexer.full_start(); let mut first_modifier = None; if self.lexer.token == T::TAt || self.is_modifier_kind() { - first_modifier = self.skip_parameter_modifiers(&mut parameter)?; + // `parseParameter` + first_modifier = + self.skip_parameter_modifiers(&mut parameter, crate::AwaitOrYield::AllowIdent)?; } - let is_this = self.lexer.token == T::TThis; + let is_this = self.token() == T::TThis; if self.lexer.token == T::TDotDotDot { parameter.rest_loc = self.lexer.loc(); self.lexer.next()?; @@ -648,19 +709,17 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(()) } - /// The modifiers of `parseParameterEx`. Returns `Loc` of the first. + /// The modifiers of `parseParameterEx`, which are parsed in the [Await] context `outer_await` + /// (`inOuterAwaitContext`). Returns `Loc` of the first. #[cold] #[inline(never)] fn skip_parameter_modifiers( &mut self, parameter: &mut Param, + outer_await: crate::AwaitOrYield, ) -> Result, Error> { let mut modifiers: Vec = Vec::new(); - let first = self.skip_modifiers( - AllowDecorators::Yes, - PermitConstAsModifier::No, - &mut modifiers, - )?; + let first = self.parse_modifiers_of_parameter(outer_await, &mut modifiers)?; for modifier in &modifiers { parameter.flags |= modifier.flag; } @@ -670,6 +729,19 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(first) } + /// The same, added to `modifiers`. + pub(crate) fn parse_modifiers_of_parameter( + &mut self, + outer_await: crate::AwaitOrYield, + modifiers: &mut Vec, + ) -> Result, Error> { + let inner_await = + core::mem::replace(&mut self.fn_or_arrow_data_parse.allow_await, outer_await); + let first = self.skip_modifiers(AllowDecorators::Yes, PermitConstAsModifier::No, modifiers); + self.fn_or_arrow_data_parse.allow_await = inner_await; + first + } + /// `parseModifiersEx(allowDecorators, permitConstAsModifier, false)`. Returns `Loc` of the /// first modifier. #[cold] @@ -690,7 +762,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut has_static = false; loop { if allow_decorators && self.lexer.token == T::TAt && !has_trailing_modifier { - let decorators = self.parse_detached(|p| p.parse_type_script_decorators())?; + let decorators = self.parse_type_script_decorators()?; for &decorator in decorators.iter() { let at_sign = self.noted(decorator.loc, crate::sema::Mark::AtSign); let end = self.noted(decorator.loc, crate::sema::Mark::DecoratorEnd); @@ -708,7 +780,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> continue; } // `tryParseModifier` - let is_modifier = if self.lexer.token == T::TConst && permit_const_as_modifier { + let is_modifier = if self.token() == T::TConst && permit_const_as_modifier { // `nextTokenIsOnSameLineAndCanFollowModifier` self.next_token_matches(|p| { !p.lexer.has_newline_before @@ -746,32 +818,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(first) } - /// Runs `parse` on an expression or a function body that appears inside a type, and returns the - /// result. It is not part of the AST. Keep mode stores it for the lowering pass. - /// Speculative parsing only restores the lexer when it backtracks. So during a speculative - /// parse, everything `parse` did to the parser's state is undone immediately, except for the - /// lexer's position. - #[cold] - #[inline(never)] - pub(crate) fn parse_detached( - &mut self, - parse: impl FnOnce(&mut Self) -> Result, - ) -> Result { - if !self.lexer.is_log_disabled { - return parse(self); - } - let snapshot = self.parser_snapshot(); - let result = parse(self); - let mut after = self.lexer.snapshot(); - self.restore_parser_snapshot_but_for_notes(snapshot); - let result = result?; - // The comments scanned along the way are discarded with the rest. - after.all_comments_len = self.lexer.all_comments.len(); - after.comments_to_preserve_before_len = self.lexer.comments_to_preserve_before.len(); - self.lexer.restore(&after); - Ok(result) - } - /// Called on the token after the "[" of an object type member. False for an index signature ("[key: string]", /// `isUnambiguouslyIndexSignature`) and for a mapped type ("[K in T]"), which `can_be_mapped_type` allows (`isStartOfMappedType`). #[cold] @@ -792,12 +838,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[inline(never)] fn skip_computed_property_name(&mut self) -> Result { self.lexer.expect(T::TOpenBracket)?; - let name = self.parse_detached(|p| { - let old_allow_in = core::mem::replace(&mut p.allow_in, true); - let name = p.parse_expr(Level::Lowest); - p.allow_in = old_allow_in; - name - })?; + let name = self.parse_expression_of_computed_name()?; self.lexer.expect(T::TCloseBracket)?; Ok(name) } @@ -808,7 +849,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[inline(never)] fn skip_initializer_in_signature(&mut self) -> Result { self.lexer.expect(T::TEquals)?; - self.parse_detached(|p| p.parse_expr(Level::Comma)) + self.parse_expr(Level::Comma) } /// This is a spot where the TypeScript grammar is highly ambiguous. Here are @@ -843,11 +884,14 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> None }; + // `isMissingNodeList(Parameters)`: see `skip_parameters_of_fn_type`. + let lacks_parameters = KEEP && self.lexer.token != T::TOpenParen; if allow_fn_type - && (self.try_skip_type_script_arrow_args_with_backtracking(head.is_some())? - || (self.is_tolerant() - && !self.lexer.is_log_disabled - && self.skip_fn_type_args_without_arrow(head.is_some())?)) + && (if self.is_tolerant() { + self.skip_parameters_of_fn_type(head.is_some())? + } else { + self.try_skip_type_script_arrow_args_with_backtracking()? + }) { let parameters = if KEEP { self.type_syntax_mut().last_params.take() @@ -859,7 +903,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> *result.expect("infallible: GET_METADATA implies Some") = Metadata::MFunction; } if KEEP { + let blocks = + lacks_parameters || self.type_syntax_mut().last_type_blocks_arrow_function(); self.emit_fn_type(head, open_paren, parameters); + self.type_syntax_mut().last_type_lacks_parameters = blocks; } } else { self.lexer.expect(T::TOpenParen)?; @@ -883,14 +930,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(()) } - /// `parseFunctionOrConstructorType`, where the speculative parse of "(..) =>" failed. Whether a - /// "(" starts a function type is decided by lookahead, not by the "=>" - /// (`isStartOfFunctionTypeOrConstructorType`). After "new" or "" (`has_head`) it always - /// does. If it does, the parameters are skipped, a missing "=>" is reported - /// (`shouldParseReturnType`), and the return type comes next. - #[cold] + /// `parseFunctionOrConstructorType` in tolerant mode. Whether a "(" starts a function type is + /// decided by lookahead, not by the "=>" (`isStartOfFunctionTypeOrConstructorType`). After + /// "new" or "" (`has_head`) it always does. If it does, the parameters are skipped, a + /// missing "=>" is reported (`shouldParseReturnType`), and the return type comes next. #[inline(never)] - fn skip_fn_type_args_without_arrow(&mut self, has_head: bool) -> Result { + fn skip_parameters_of_fn_type(&mut self, has_head: bool) -> Result { if self.lexer.token != T::TOpenParen { if !has_head { return Ok(false); @@ -910,19 +955,14 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } /// Lookahead with `nextIsUnambiguouslyStartOfFunctionType`, at a "(". - #[cold] #[inline(never)] fn is_unambiguously_start_of_function_type(&mut self) -> bool { - let (here, swallowed) = (self.lexer.snapshot(), self.lexer.swallowed); - // `skipParameterStart` parses a whole binding pattern. - let noted = self.type_syntax_checkpoint(); - self.lexer.is_log_disabled = true; + // `skipParameterStart` parses a whole binding pattern, with the expressions in it. + let snapshot = self.parser_snapshot(); let found = self .next_is_unambiguously_start_of_function_type() .unwrap_or(false); - self.lexer.restore(&here); - self.rewind_type_syntax(¬ed); - self.lexer.swallowed = swallowed; + self.restore_parser_snapshot(snapshot); found } @@ -944,13 +984,16 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if self.lexer.token == T::TDotDotDot { self.lexer.next()?; } - if self.is_identifier_in_context() || self.lexer.token == T::TThis { + if self.is_identifier_in_context() || self.token() == T::TThis { self.lexer.next()?; } else if matches!(self.lexer.token, T::TOpenBracket | T::TOpenBrace) { - // Only a binding pattern without errors counts. - let swallowed = self.lexer.swallowed; + // Only a binding pattern without parse errors counts. + let logged = self.log().msgs.len(); self.skip_type_script_binding()?; - if self.lexer.swallowed != swallowed { + if self.log().msgs[logged..] + .iter() + .any(crate::sema::is_parse_error) + { return Ok(false); } } else { @@ -978,14 +1021,13 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[inline(never)] fn fn_type_after_operator_error(&mut self, in_union: bool) -> Option<(bun_ast::Loc, u32)> { // `isStartOfFunctionTypeOrConstructorType` - let token = self.lexer.token; - let is_constructor = match token { + let is_constructor = match self.token() { T::TLessThan => false, T::TOpenParen if self.is_unambiguously_start_of_function_type() => false, T::TNew => true, T::TIdentifier if self.lexer.is_contextual_keyword(b"abstract") - && self.next_token_matches(|p| p.lexer.token == T::TNew) => + && self.next_token_matches(|p| p.token() == T::TNew) => { true } @@ -1056,12 +1098,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> /// `createIdentifierWithDiagnostic(Type_expected)`, where no name starts: the error. fn report_type_expected(&mut self) -> Result<(), Error> { - // During a speculative parse nothing is reported. If it succeeds, it is run again to report - // its errors. - if self.lexer.is_log_disabled { - self.lexer.swallowed += 1; - return Ok(()); - } // At the end of the file the error is at the end of the previous token. if self.lexer.token == T::TEndOfFile { let loc = self.lexer.full_start(); @@ -1101,6 +1137,29 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(()) } + /// `parseTypeArgumentsOfTypeReference`, after the name "const". What `checkGrammarTypeArguments` + /// reports is kept with the nodes, not logged: `const<>` is a const assertion too + /// (`isConstTypeReference`), and `checkAssertion` does not check the type of one. + #[cold] + #[inline(never)] + fn skip_type_arguments_of_const(&mut self) -> Result<(), Error> { + if !KEEP { + let _ = self.skip_type_script_type_arguments::()?; + return Ok(()); + } + let reference = self.take_reference(); + let mut grammar_error = None; + let has_arguments = + self.skip_type_script_type_arguments_unchecked::(&mut grammar_error)?; + self.attach_type_args(reference, has_arguments); + if let Some((range, code)) = grammar_error { + let (start, end) = (range.loc.start as u32, range.end().start as u32); + let file = &mut self.type_syntax_mut().b.file; + file.error(bun_sema::hir::DiagnosticKind::Grammar, start, end, code); + } + Ok(()) + } + /// `parseEntityName` of a type reference, after a dot that is not followed by an identifier or /// keyword, and `parseTypeArgumentsOfTypeReference`. #[cold] @@ -1310,8 +1369,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // Reported when the type is cloned (2880). assert_keyword_loc = Some(self.lexer.loc()); self.lexer.next_token()?; - } else if self.lexer.is_log_disabled { - return Err(crate::Error::Backtrack); } else { // 'with' expected. let (range, before) = (self.lexer.range(), self.lexer.prev_error_loc); @@ -1412,17 +1469,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> ) -> Result<(), Error> { let saved_contexts = self.enter_list(ListKind::TupleElementTypes); while self.lexer.token != T::TCloseBracket { - if self.lexer.is_log_disabled { - // A speculative parse fails at the missing "]". - if !self.is_list_element(ListKind::TupleElementTypes, false) { - break; - } - } else { - match self.classify_list_token(ListKind::TupleElementTypes)? { - ListStep::Element => {} - ListStep::Skipped => continue, - ListStep::Over => break, - } + match self.classify_list_token(ListKind::TupleElementTypes)? { + ListStep::Element => {} + ListStep::Skipped => continue, + ListStep::Over => break, } let element_start = self.lexer.loc(); let element = self.skip_tuple_element::()?; @@ -1493,7 +1543,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.emit_optional_type(ty, pos); } else { element.is_optional = true; - self.type_syntax_mut().last_type = ty; + self.type_syntax_mut().set_last_type(ty); } } self.finish_last_type(); @@ -1535,26 +1585,18 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> ] } - /// At a reserved word written with an escape, where a type starts. `parseNonArrayType` and - /// `isStartOfFunctionTypeOrConstructorType` take these as the keyword. Any other is the name of - /// a type reference, and so are these where they are the name of a tuple element or of the - /// parameter of an index signature. + /// At a reserved word written with an escape, where a type starts. `parseNonArrayType` and, + /// where it is asked (`allow_fn_type`), `isStartOfFunctionTypeOrConstructorType` take these as + /// the keyword. Any other is the name of a type reference, and so are these where they are the + /// name of a tuple element or of the parameter of an index signature. #[cold] #[inline(never)] - fn unescape_keyword_of_type(&mut self, opts: SkipTypeOptionsBitset) { - let starts_type = matches!( - crate::lexer::keyword(self.lexer.identifier), - Some( - T::TVoid - | T::TNull - | T::TTrue - | T::TFalse - | T::TThis - | T::TTypeof - | T::TImport - | T::TNew - ) - ); + fn unescape_keyword_of_type(&mut self, opts: SkipTypeOptionsBitset, allow_fn_type: bool) { + let starts_type = match self.token() { + T::TVoid | T::TNull | T::TTrue | T::TFalse | T::TThis | T::TTypeof | T::TImport => true, + T::TNew => allow_fn_type, + _ => false, + }; if !starts_type || !self.is_tolerant() { return; } @@ -1637,7 +1679,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> loop { if self.lexer.token == T::TEscapedKeyword { - self.unescape_keyword_of_type(opts); + self.unescape_keyword_of_type(opts, allow_fn_type); } if KEEP { pos = self.token_start(); @@ -1717,12 +1759,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // `parseTypeReference`: "const" is a name like any other. if self.is_tolerant() && !self.lexer.has_newline_before { - let reference = if KEEP { self.take_reference() } else { None }; - let has_arguments = - self.skip_type_script_type_arguments::()?; - if KEEP { - self.attach_type_args(reference, has_arguments); - } + self.skip_type_arguments_of_const::()?; } } @@ -2090,7 +2127,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } else { (StoreStr::EMPTY, 0) }; - self.lexer.expect(T::TIdentifier)?; + if self.lexer.token == T::TPrivateIdentifier && self.is_tolerant() { + self.skip_private_identifier_as_name()?; + } else { + self.lexer.expect(T::TIdentifier)?; + } let mut has_constraint = false; if self.lexer.is_keyword(T::TExtends) { has_constraint = self @@ -2143,7 +2184,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.lexer.next()?; // "let foo: abstract new () => {}" added in TypeScript 4.2 - if self.lexer.token == T::TNew && allow_fn_type { + if allow_fn_type + && (self.lexer.token == T::TNew + || (self.is_tolerant() && self.token() == T::TNew)) + { self.lexer.keyword_was_taken(escaped_word); is_abstract = true; abstract_pos = pos; @@ -2159,18 +2203,25 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // "function assert(x: boolean): asserts x" // "function assert(x: boolean): asserts x is boolean" // TypeScript's parser (`parseNonArrayType`) accepts this in any type position and leaves the error to the - // checker, so tolerant mode does the same. - if (opts.contains(SkipTypeOptions::IsReturnType) || self.is_tolerant()) - && !self.lexer.has_newline_before - && (self.lexer.token == T::TIdentifier - || self.lexer.token == T::TThis) + // checker, so tolerant mode does the same, before any word + // (`nextTokenIsIdentifierOrKeywordOnSameLine`). + if !self.lexer.has_newline_before + && (if self.is_tolerant() { + self.is_identifier_or_keyword() + } else { + opts.contains(SkipTypeOptions::IsReturnType) + && (self.lexer.token == T::TIdentifier + || self.lexer.token == T::TThis) + }) { self.lexer.keyword_was_taken(escaped_word); if KEEP { - predicate_subject = if self.lexer.token == T::TThis { - StoreStr::new(b"this") - } else { - StoreStr::new(self.lexer.identifier) + predicate_subject = match self.lexer.token { + T::TThis => StoreStr::new(b"this"), + T::TIdentifier | T::TPrivateIdentifier => { + StoreStr::new(self.lexer.identifier) + } + _ => StoreStr::EMPTY, }; self.emit_predicate_of( predicate_subject, @@ -2179,7 +2230,15 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> pos, ); } - self.lexer.next()?; + // `parseAssertsTypePredicate`: `parseIdentifier` + match self.lexer.token { + T::TIdentifier | T::TThis => self.lexer.next()?, + T::TPrivateIdentifier => { + self.skip_private_identifier_as_name()?; + } + // A reserved word is no name, and is not consumed. + _ => self.lexer.expect(T::TIdentifier)?, + } asserts_name = true; } else if KEEP { self.emit_type_ref(predicate_subject, pos); @@ -2367,7 +2426,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> .expect("infallible: GET_METADATA implies Some") = Metadata::MObject; } - if self.lexer.token == T::TImport { + if self.lexer.token == T::TImport + || (self.is_tolerant() && self.token() == T::TImport) + { // "typeof import('fs')" typeof_pos = Some(pos); continue; @@ -3106,12 +3167,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if keeps && (tolerant || self.is_start_of_computed_member_name(can_be_mapped_type)) { // `parseComputedPropertyName` - member.computed_name = Some(self.parse_detached(|p| { - let old_allow_in = core::mem::replace(&mut p.allow_in, true); - let name = p.parse_expr(Level::Lowest); - p.allow_in = old_allow_in; - name - })?); + member.computed_name = Some(self.parse_expression_of_computed_name()?); } else { self.skip_type_script_type_with_opts::( Level::Lowest, @@ -3238,6 +3294,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if tolerant { // `parsePropertyName` after modifiers: the name is missing, and the // token is not consumed. + if keeps { + member.name = Some(self.missing_member_word()); + } self.lexer.expect(T::TIdentifier)?; } else { self.lexer.unexpected()?; @@ -3392,11 +3451,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> { return false; } - let (here, swallowed) = (self.lexer.snapshot(), self.lexer.swallowed); + let here = self.lexer.snapshot(); self.lexer.is_log_disabled = true; let found = self.scan_start_of_mapped_type().unwrap_or(false); self.lexer.restore(&here); - self.lexer.swallowed = swallowed; found } @@ -3544,18 +3602,16 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[cold] #[inline(never)] fn skip_accessor_body_in_type(&mut self) -> Result { - self.parse_detached(|p| { - // `parse_fn_body` requires the parameter scope to enclose the body scope and to start - // before it. - let before_body = bun_ast::Loc { - start: p.lexer.loc().start - 1, - }; - let scope_index = - p.push_scope_for_parse_pass(bun_ast::scope::Kind::FunctionArgs, before_body)?; - let body = p.parse_fn_body(&mut FnOrArrowDataParse::default())?; - p.pop_and_discard_scope(scope_index); - Ok(body) - }) + // `parse_fn_body` requires the parameter scope to enclose the body scope and to start + // before it. + let before_body = bun_ast::Loc { + start: self.lexer.loc().start - 1, + }; + let scope_index = + self.push_scope_for_parse_pass(bun_ast::scope::Kind::FunctionArgs, before_body)?; + let body = self.parse_fn_body(&mut FnOrArrowDataParse::default())?; + self.pop_and_discard_scope(scope_index); + Ok(body) } // This is the type parameter declarations that go with other symbol @@ -3797,13 +3853,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut result = SkipTypeParameterResult::CouldBeTypeCast; if is_at_greater_than(self) { - // "<>" is not a parse error. It never starts an arrow function - // (`isParenthesizedArrowFunctionExpression`). - if self.lexer.is_log_disabled - && !flags.contains(TypeParameterFlag::ALLOW_EMPTY_TYPE_PARAMETERS) - { - self.lexer.expected(T::TIdentifier)?; - } + // "<>" is not a parse error. // `checkGrammarClassLikeDeclaration` looks at the heritage clauses first: `parse_class` // reports it. The checker finds the empty list of a function in the source text. if keeps @@ -3828,10 +3878,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let saved_contexts = self.enter_list(ListKind::TypeParameters); let mut is_empty = true; while !is_at_greater_than(self) { - // The modifiers that are reserved words. - if self.lexer.token == T::TEscapedKeyword && !self.lexer.is_keyword(T::TIn) { - self.lexer.is_keyword(T::TConst); - } match self.classify_list_token(ListKind::TypeParameters)? { ListStep::Element => {} ListStep::Skipped => continue, @@ -3918,6 +3964,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // `parseIdentifier` if self.is_identifier_in_context() { + self.new_identifier(); parameter.name = StoreStr::new(self.lexer.identifier); parameter.loc = self.lexer.loc(); self.lexer.next()?; @@ -3944,7 +3991,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // An expression is parsed as an expression, and `checkTypeParameter` expects a // type. let expression = self.lexer.range(); - self.parse_detached(|p| p.parse_expr(Level::Prefix))?; + self.parse_expr(Level::Prefix)?; self.lexer.ts_grammar_error(expression, 1110); } } @@ -4014,7 +4061,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let name = self.lexer.identifier; let name_loc = self.lexer.loc(); - self.lexer.expect(T::TIdentifier)?; + self.expect_identifier()?; if opts.scope.is_module() { self.local_type_names.put(name, true)?; @@ -4074,7 +4121,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> ) -> Result<(), Error> { let name = self.lexer.identifier; let name_loc = self.lexer.loc(); - self.lexer.expect(T::TIdentifier)?; + self.expect_identifier()?; if opts.scope.is_module() { self.local_type_names.put(name, true)?; @@ -4178,10 +4225,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if !self.lexer.is_keyword(T::TExtends) && !self.lexer.is_contextual_keyword(b"implements") { - // A speculative parse fails at the missing "{". - if self.lexer.is_log_disabled - || self.classify_list_token(ListKind::HeritageClauses)? != ListStep::Skipped - { + if self.classify_list_token(ListKind::HeritageClauses)? != ListStep::Skipped { break; } continue; @@ -4205,11 +4249,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // `checkGrammarExpressionWithTypeArguments`, of the first element that has an error. let mut element_error: Option<(bun_ast::Range, u32)> = None; loop { - if self.lexer.is_log_disabled { - if !self.is_list_element(ListKind::HeritageClauseElement, false) { - break; - } - } else if !self.skip_to_list_element(ListKind::HeritageClauseElement)? { + if !self.skip_to_list_element(ListKind::HeritageClauseElement)? { break; } let element_start = self.lexer.loc(); @@ -4270,11 +4310,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut grammar_error = None; if !self.is_at_entity_name_expression() { let scope_index = self.scopes_in_order.len(); - let (expression, _) = + let (expression, has_arguments) = self.parse_expression_with_type_arguments(is_checked, &mut grammar_error)?; self.discard_scopes_up_to(scope_index); if keeps { - self.emit_heritage_expression(expression, pos); + self.emit_heritage_expression(expression, has_arguments, pos); self.finish_last_type(); } return Ok(grammar_error); @@ -4328,8 +4368,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> grammar_error: &mut Option<(bun_ast::Range, u32)>, ) -> Result<(bun_ast::Expr, bool), Error> { let (start, is_at_import) = (self.lexer.loc(), self.lexer.token == T::TImport); + let logged = self.log().msgs.len(); // `parseLeftHandSideExpressionOrHigher` - let mut expression = self.parse_detached(|p| p.parse_expr(Level::New))?; + let mut expression = self.parse_expr(Level::New)?; let has_arguments = self.skip_type_arguments_of_heritage_element(is_checked, grammar_error)?; // The keyword `import` by itself is a missing expression. @@ -4338,7 +4379,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> start: start.start + b"import".len() as i32, }; self.note_end(&mut expression.loc, keyword_end); - if has_arguments { + if has_arguments || self.take_back_import_with_type_arguments(logged) { *grammar_error = Some((self.lexer.range_from(start), 1326)); } } @@ -4364,13 +4405,18 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } /// `IsEntityNameExpression`: whether the expression that starts here is `A.B.C` and nothing - /// more, but for type arguments at its end. + /// more, but for type arguments at its end. Lookahead only. fn is_at_entity_name_expression(&mut self) -> bool { if self.lexer.token != T::TIdentifier { return false; } - let old_lexer = self.lexer.snapshot(); - self.lexer.is_log_disabled = true; + let snapshot = self.parser_snapshot(); + let is_entity_name = self.scan_entity_name_expression(); + self.restore_parser_snapshot(snapshot); + is_entity_name + } + + fn scan_entity_name_expression(&mut self) -> bool { let mut is_name = self.lexer.next().is_ok(); while is_name && matches!(self.lexer.token, T::TDot | T::TQuestionDot) { is_name = self.lexer.next().is_ok() @@ -4382,17 +4428,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if is_name && matches!(self.lexer.token, T::TLessThan | T::TLessThanLessThan) && !self.lexer.is_javascript_file() - { - let (noted, swallowed) = (self.type_syntax_checkpoint(), self.lexer.swallowed); - let is_part_of_expression = self + && self .skip_type_script_type_arguments_with_backtracking(false) - .is_ok(); - self.rewind_type_syntax(¬ed); - self.lexer.swallowed = swallowed; - if !is_part_of_expression { - self.lexer.restore(&old_lexer); - return true; - } + .is_err() + { + return true; } // `parseMemberExpressionRest` and `parseCallExpressionRest` continue at these tokens. let continues = match self.lexer.token { @@ -4405,7 +4445,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> T::TExclamation => !self.lexer.has_newline_before, _ => false, }; - self.lexer.restore(&old_lexer); is_name && !continues } @@ -4493,6 +4532,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // list. Nested type arguments ("Array>()") still work // because the inner list is in a type context and already stripped one // ">" from the ">>" before we see the outer closer here. + if self.lexer.token != T::TGreaterThan && self.is_tolerant() { + return Err(crate::Error::Backtrack); + } if IS_INSIDE_JSX_ELEMENT { self.lexer.expect_inside_jsx_element(T::TGreaterThan)?; } else { @@ -4531,6 +4573,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // Both return `Err` only for stack and memory exhaustion, which are not properties of the attempt. If they counted as a failed // attempt, the caller would parse the same text another way, and where that way needs less stack per level it would end in an // ordinary syntax error for valid code. + // An ordinary build disables the log, and the first error ends the attempt. Tolerant mode: see `try_parse`. #[inline] fn lexer_backtracker_bool(&mut self, func: F) -> Result @@ -4538,12 +4581,13 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> F: Fn(&mut Self) -> Result, { self.mark_type_script_only(); + if self.is_tolerant() { + return Ok(self.try_parse(func)?.is_some()); + } // The Lexer // holds `&mut Log`, so backtracking goes through a POD `LexerSnapshot` + `restore()`. let old_lexer = self.lexer.snapshot(); - let noted = self.type_syntax_checkpoint(); let old_log_disabled = self.lexer.is_log_disabled; - let old_swallowed = self.lexer.swallowed; self.lexer.is_log_disabled = true; let mut backtrack = false; let mut exhausted = None; @@ -4559,25 +4603,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if backtrack { self.lexer.restore(&old_lexer); - self.rewind_type_syntax(¬ed); - // `rewind` drops the errors. - self.lexer.swallowed = old_swallowed; } self.lexer.is_log_disabled = old_log_disabled; if let Some(err) = exhausted { return Err(err); } - // Only changes in tolerant mode. - if self.lexer.swallowed != old_swallowed && !backtrack && !old_log_disabled { - // The rerun produces everything again. - self.rewind_type_syntax(¬ed); - self.log_errors_of_successful_trial(&old_lexer, &|p: &mut Self| func(p).is_ok()); - } - if !backtrack { - self.release_type_syntax_checkpoint(¬ed); - } - Ok(!backtrack) } @@ -4587,10 +4618,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> F: Fn(&mut Self) -> Result, { self.mark_type_script_only(); + if self.is_tolerant() { + let skipped = self.try_parse(func)?; + return Ok(skipped.unwrap_or(SkipTypeParameterResult::DidNotSkipAnything)); + } let old_lexer = self.lexer.snapshot(); - let noted = self.type_syntax_checkpoint(); let old_log_disabled = self.lexer.is_log_disabled; - let old_swallowed = self.lexer.swallowed; self.lexer.is_log_disabled = true; let mut backtrack = false; let mut exhausted = None; @@ -4607,49 +4640,37 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if backtrack { self.lexer.restore(&old_lexer); - self.rewind_type_syntax(¬ed); - // `rewind` drops the errors. - self.lexer.swallowed = old_swallowed; } self.lexer.is_log_disabled = old_log_disabled; if let Some(err) = exhausted { return Err(err); } - // Only changes in tolerant mode. - if self.lexer.swallowed != old_swallowed && !backtrack && !old_log_disabled { - // The rerun produces everything again. - self.rewind_type_syntax(¬ed); - self.log_errors_of_successful_trial(&old_lexer, &|p: &mut Self| func(p).is_ok()); - } - if !backtrack { - self.release_type_syntax_checkpoint(¬ed); - } - Ok(result) } - /// `mark`, `rewind`: TypeScript keeps the errors of a speculative parse that succeeds. `trial` - /// succeeded from `start` on with the log disabled, so it is rerun with the log enabled. - #[cold] + /// `mark` and `rewind`, in tolerant mode. `trial` runs like the rest of the parser: it reports + /// its errors and recovers from them, and fails only where it says so. `None`: it failed, and + /// all it did is undone, its errors included. #[inline(never)] - fn log_errors_of_successful_trial( + fn try_parse( &mut self, - start: &crate::lexer::LexerSnapshot<'a>, - trial: &dyn Fn(&mut Self) -> bool, - ) { - let end = self.lexer.start; - self.lexer.restore(start); + trial: impl FnOnce(&mut Self) -> Result, + ) -> Result, Error> { let snapshot = self.parser_snapshot(); - if trial(self) && self.lexer.start == end { - return self.release_parser_snapshot(&snapshot); + match trial(self) { + Ok(result) => { + self.release_parser_snapshot(&snapshot); + Ok(Some(result)) + } + Err(err) => { + self.restore_parser_snapshot(snapshot); + if matches!(err, Error::StackOverflow | Error::Alloc(_)) { + return Err(err); + } + Ok(None) + } } - // Error recovery, which is off while the log is disabled, took a different path. Keeps the - // result of the first run, without errors. - self.restore_parser_snapshot(snapshot); - self.lexer.is_log_disabled = true; - let _ = trial(self); - self.lexer.is_log_disabled = false; } pub(crate) fn skip_type_script_type_parameters_then_open_paren_with_backtracking( @@ -4693,17 +4714,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(true) } - /// `has_head`: "new" or type parameters precede the "(". - pub(crate) fn skip_type_script_arrow_args_with_backtracking( - &mut self, - has_head: bool, - ) -> Result { - self.lexer.expect(T::TOpenParen)?; - // `skipParameterStart` parses no decorators. - if self.lexer.token == T::TAt && !has_head { - return Err(crate::Error::Backtrack); - } - self.skip_typescript_fn_args_after_open_paren()?; + pub(crate) fn skip_type_script_arrow_args_with_backtracking(&mut self) -> Result { + self.skip_typescript_fn_args()?; if self.lexer.expect(T::TEqualsGreaterThan).is_err() { return Err(crate::Error::Backtrack); } @@ -4799,6 +4811,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> /// that its members stay untouched. The outcome is memoized by the offset /// of the ":" in `ts_conditional_arrow_attempts`, so the real parse does not /// repeat the attempts nested inside the body. + /// + /// An ordinary build gives up at the first error. Tolerant mode gives up only where + /// `parseParenthesizedArrowFunctionExpression` returns nil. pub(crate) fn is_type_script_arrow_return_type_after_question_and_before_colon( &mut self, arrow_data: &FnOrArrowDataParse, @@ -4814,18 +4829,27 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } let snapshot = self.parser_snapshot(); - self.lexer.is_log_disabled = true; + let tolerant = self.is_tolerant(); + // Tolerant mode logs the errors it recovers from. The snapshot undoes them too. + self.lexer.is_log_disabled |= !tolerant; let mut data = arrow_data.clone(); let result: Result<(), Error> = (|| { self.lexer.expect(T::TColon)?; + let type_start = self.lexer.loc(); self.skip_typescript_return_type()?; + if tolerant { + self.check_token_after_arrow_return_type(type_start)?; + } self.parse_arrow_body_with_flags( &mut [], &mut data, bun_ast::expr::EFlags::AfterQuestionAndBeforeColon, )?; // The ":" that pairs with the "?" + if tolerant && self.lexer.token != T::TColon { + return Err(Error::Backtrack); + } self.lexer.expect(T::TColon)?; Ok(()) })(); @@ -4884,9 +4908,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> pub(crate) fn try_skip_type_script_arrow_args_with_backtracking( &mut self, - has_head: bool, ) -> Result { - self.lexer_backtracker_bool(|p| p.skip_type_script_arrow_args_with_backtracking(has_head)) + self.lexer_backtracker_bool(Self::skip_type_script_arrow_args_with_backtracking) } pub(crate) fn try_skip_type_script_constraint_of_infer_type_with_backtracking( diff --git a/src/js_parser/parse/parse_stmt.rs b/src/js_parser/parse/parse_stmt.rs index d98ce05993df..6fe5808cd4ee 100644 --- a/src/js_parser/parse/parse_stmt.rs +++ b/src/js_parser/parse/parse_stmt.rs @@ -165,9 +165,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Self::parse_declaration_worker(p, opts, is_async) } - /// The keywords of `parseModifiersEx`, from the current token up to one that `parse_stmt` takes - /// itself: `export`, `declare`, `const` before `enum`, `async` before `function`, `abstract` - /// before `class`. Returns whether it consumed any, and whether `async` is one of the + /// `parseModifiersEx`, from the current token up to a keyword that `parse_stmt` takes itself: + /// `export`, `declare`, `const` before `enum`, `async` before `function`, `abstract` before + /// `class`. Returns whether it consumed any keyword, and whether `async` is one of the /// modifiers. Tolerant mode only. #[cold] #[inline(never)] @@ -177,6 +177,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut has_static = p.statement_has_modifier(Modifier::STATIC); loop { Self::unescape_keyword_of_statement(p); + if p.lexer.token == T::TAt && !Self::has_trailing_modifier(p, opts) { + Self::more_decorators(p, opts)?; + continue; + } if !p.is_at_modifier(has_static) { break; } @@ -206,6 +210,46 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok((has_any, is_async)) } + /// `hasTrailingModifier` of `parseModifiersEx`: whether, in what has been consumed so far of + /// the statement being parsed, a keyword follows a decorator that follows a keyword. + #[cold] + #[inline(never)] + fn has_trailing_modifier(p: &Self, opts: &ParseStatementOptions<'a>) -> bool { + let (Some(decorators), Some(syntax)) = (&opts.ts_decorators, &p.type_syntax) else { + return false; + }; + let keywords = &syntax.statement_modifiers[syntax.statement_modifiers_base..]; + let (Some(first), Some(last)) = (keywords.first(), keywords.last()) else { + return false; + }; + decorators.values.iter().any(|decorator| { + let at = p.real_loc(decorator.loc).start; + first.loc.start < at && at < last.loc.start + }) + } + + /// `parseTypeAliasDeclaration`, at `type`, for the statement at `loc`. Tolerant mode only. + #[cold] + #[inline(never)] + fn parse_type_alias_declaration( + p: &mut Self, + scope: StatementScope, + loc: bun_ast::Loc, + ) -> Result { + let keyword_loc = p.lexer.loc(); + p.lexer.next_token()?; + if p.lexer.has_newline_before { + let range = p.lexer.range(); + p.lexer.ts_error(range, 1142); + } + let mut stmt_opts = ParseStatementOptions { + scope, + ..Default::default() + }; + p.skip_type_script_type_stmt(&mut stmt_opts, keyword_loc)?; + Ok(p.type_script_statement(loc)) + } + /// `parseDeclarationWorker`, after decorators or modifiers. `is_async`: `async` is one of the /// modifiers. Tolerant mode only. #[cold] @@ -215,6 +259,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> opts: &mut ParseStatementOptions<'a>, is_async: bool, ) -> Result { + let loc = p.lexer.loc(); let word = p.lexer.identifier; // Whether what follows can still be a class. `None`: no declaration follows. let can_be_class = match p.lexer.token { @@ -252,7 +297,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> { // `parseVariableStatement`: after modifiers, `using` starts a declaration list // regardless of the next token. - let loc = p.lexer.loc(); p.lexer.next_token()?; opts.is_using_statement = true; let decls = p.parse_and_declare_decls(js_ast::symbol::Kind::Constant, opts)?; @@ -266,6 +310,41 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> loc, )); } + // The keyword alone decides: only `parseStatement` asks `isStartOfDeclaration`. + match p.lexer.token { + T::TImport => return Self::t_import(p, opts, loc, true), + T::TIdentifier => match word { + b"interface" => { + p.lexer.next_token()?; + let mut stmt_opts = ParseStatementOptions { + scope: opts.scope, + ..Default::default() + }; + p.skip_type_script_interface_stmt(&mut stmt_opts, loc)?; + return Ok(p.type_script_statement(loc)); + } + b"type" => return Self::parse_type_alias_declaration(p, opts.scope, loc), + b"namespace" | b"module" => { + p.lexer.next_token()?; + let is_module = word == b"module"; + return p.parse_type_script_namespace_stmt(loc, opts, false, is_module); + } + b"global" => { + p.lexer.next()?; + let keyword = js_lexer::TypescriptStmtKeyword::TsStmtGlobal; + if let Some(stmt) = + Self::parse_stmt_fallthrough_ts_keyword(p, opts, loc, keyword)? + { + return Ok(stmt); + } + // `parseAmbientExternalModuleDeclaration`: without a "{" there is no body. + p.lexer.expect_or_insert_semicolon()?; + return Ok(p.keep_global(loc, loc, None, opts.is_export)); + } + _ => {} + }, + _ => {} + } let mut stmt = p.parse_stmt(opts)?; // `parseFunctionDeclaration`: `modifierListHasAsync`, with `async` at any position among // the modifiers. @@ -284,84 +363,44 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.expected(T::TClass)?; return Ok(()); } - if let Some(decorators) = opts.ts_decorators.take() - && let Some(first) = decorators.values.first() - { - let at_sign = |p: &Self, decorator: &Expr| match p - .noted(decorator.loc, crate::sema::Mark::AtSign) - { - Some(at_sign) => bun_ast::Loc { - start: at_sign as i32, - }, - None => p.real_loc(decorator.loc), - }; - // `checkJSDecoratorSyntax` - if p.lexer.is_javascript_file() { - let loc = at_sign(p, first); - p.lexer - .ts_grammar_error(bun_ast::Range { loc, len: 1 }, 1206); - } + if let Some(decorators) = opts.ts_decorators.take() { let end = p.lexer.full_start(); for decorator in decorators.values { p.note_stray_decorator(decorator, end); - let loc = at_sign(p, decorator); + let loc = match p.noted(decorator.loc, crate::sema::Mark::AtSign) { + Some(at_sign) => bun_ast::Loc { + start: at_sign as i32, + }, + None => p.real_loc(decorator.loc), + }; p.push_statement_decorator(*decorator, loc); } } Ok(()) } - /// `parseModifiersEx`: decorators are modifiers, and may come after `export` or `export - /// default` as well as before. - /// They all decorate the class. The errors of `checkGrammarModifiers` about their position are - /// reported here. + /// `parseModifiersEx`: decorators are modifiers, and may come after `export` or `default` as + /// well as before. They all decorate the class. `checkGrammarModifiers` and + /// `checkJSDecoratorSyntax` report those that are misplaced. #[cold] #[inline(never)] fn more_decorators(p: &mut Self, opts: &mut ParseStatementOptions<'a>) -> Result<()> { - let mut at = p.lexer.range(); let scope_index = p.scopes_in_order.len(); let more = p.parse_type_script_decorators()?; - if let Some(first) = more.slice().first() - && let Some(end) = p.noted(first.loc, crate::sema::Mark::DecoratorEnd) - { - at.len = end as i32 - at.loc.start; - } - match opts.ts_decorators.take() { - // Before `export` and after it. + opts.ts_decorators = Some(match opts.ts_decorators.take() { Some(first) => { - Self::grammar_error(p, at, 8038); - // Related info: the first decorator of the declaration. - use crate::sema::Mark::{AtSign, DecoratorEnd}; - let decorator = first.values[0].loc; - if let (Some(start), Some(end)) = - (p.noted(decorator, AtSign), p.noted(decorator, DecoratorEnd)) - && !p.lexer.is_log_disabled - { - let r = bun_ast::Range { - loc: bun_ast::usize2loc(start as usize), - len: (end - start) as i32, - }; - let index = p.log().msgs.len() - 1; - p.lexer.add_related_info(index, r, b""); - } let mut all: Vec = first.values.to_vec(); all.extend_from_slice(more.slice()); - opts.ts_decorators = Some(DeferredTsDecorators { + DeferredTsDecorators { values: p.arena.alloc_slice_copy(&all), scope_index: first.scope_index, - }); - } - None => { - opts.ts_decorators = Some(DeferredTsDecorators { - values: p.arena.alloc_slice_copy(more.slice()), - scope_index, - }); - // "export @decorator default class Foo {}" - if p.lexer.token == T::TDefault { - Self::grammar_error(p, at, 1206); } } - } + None => DeferredTsDecorators { + values: p.arena.alloc_slice_copy(more.slice()), + scope_index, + }, + }); Ok(()) } @@ -411,7 +450,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.next()?; - if Self::IS_TYPESCRIPT_ENABLED && p.lexer.token == T::TEnum { + if Self::IS_TYPESCRIPT_ENABLED + && (p.lexer.token == T::TEnum || (p.is_tolerant() && p.lexer.is_keyword(T::TEnum))) + { p.push_statement_modifier(crate::sema::ts_syntax::Flags::CONST, loc); return p.parse_typescript_enum_stmt(loc, opts); } @@ -450,7 +491,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.next()?; let open_paren = p.lexer.loc(); p.lexer.expect(T::TOpenParen)?; - let test = p.parse_expr(Level::Lowest)?; + let test = p.parse_expr_allow_in(Level::Lowest)?; p.lexer.expect_closing(T::TCloseParen, open_paren)?; let mut stmt_opts = ParseStatementOptions { lexical_decl: LexicalDecl::AllowFnInsideIf, @@ -524,7 +565,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.expect(T::TWhile)?; let open_paren = p.lexer.loc(); p.lexer.expect(T::TOpenParen)?; - let test = p.parse_expr(Level::Lowest)?; + let test = p.parse_expr_allow_in(Level::Lowest)?; p.lexer.expect_closing(T::TCloseParen, open_paren)?; // This is a weird corner case where automatic semicolon insertion applies @@ -541,7 +582,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let open_paren = p.lexer.loc(); p.lexer.expect(T::TOpenParen)?; - let test = p.parse_expr(Level::Lowest)?; + let test = p.parse_expr_allow_in(Level::Lowest)?; p.lexer.expect_closing(T::TCloseParen, open_paren)?; let mut stmt_opts = ParseStatementOptions::default(); @@ -557,7 +598,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let open_paren = p.lexer.loc(); p.lexer.expect(T::TOpenParen)?; let test_full_start = p.lexer.full_start(); - let test = p.parse_expr(Level::Lowest)?; + let test = p.parse_expr_allow_in(Level::Lowest)?; let body_loc = p.lexer.loc(); let test_end = p.lexer.full_start(); p.lexer.expect_closing(T::TCloseParen, open_paren)?; @@ -588,7 +629,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.next()?; p.lexer.expect(T::TOpenParen)?; - let test = p.parse_expr(Level::Lowest)?; + let test = p.parse_expr_allow_in(Level::Lowest)?; p.lexer.expect(T::TCloseParen)?; let body_loc = p.lexer.loc(); @@ -638,7 +679,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> found_default = true; } else { p.lexer.expect(T::TCase)?; - value = Some(p.parse_expr(Level::Lowest)?); + value = Some(p.parse_expr_allow_in(Level::Lowest)?); p.lexer.expect(T::TColon)?; } @@ -906,6 +947,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let mut update: Option = None; // "in" expressions aren't allowed here + let old_allow_in = p.allow_in; p.allow_in = false; let mut bad_let_range: Option = None; @@ -941,7 +983,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> T::TVar => { is_var = true; p.lexer.next()?; - let mut stmt_opts = ParseStatementOptions::default(); + let mut stmt_opts = ParseStatementOptions { + is_for_loop_init: true, + ..Default::default() + }; let decls = if p.is_tolerant() && Self::no_declaration_follows(p) { bun_alloc::AstAlloc::vec() } else { @@ -960,7 +1005,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // for (const ) T::TConst => { p.lexer.next()?; - let mut stmt_opts = ParseStatementOptions::default(); + let mut stmt_opts = ParseStatementOptions { + is_for_loop_init: true, + ..Default::default() + }; let decls = if p.is_tolerant() && Self::no_declaration_follows(p) { bun_alloc::AstAlloc::vec() } else { @@ -1023,8 +1071,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } } - // "in" expressions are allowed again - p.allow_in = true; + // "in" expressions are allowed again. (`parseForOrForInOrForOfStatement` returns to the + // context of the statement: see `parse_expr_allow_in`.) + p.allow_in = old_allow_in || !p.is_tolerant(); if let Some(init) = &mut init_ { p.finish_node(&mut init.loc, init_full_start); } @@ -1079,7 +1128,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.forbid_initializers(decls_ptr.slice(), "of", false)?; p.lexer.next_token()?; - let value = p.parse_expr(Level::Comma)?; + let value = p.parse_expr_allow_in(Level::Comma)?; p.lexer.expect(T::TCloseParen)?; let mut stmt_opts = ParseStatementOptions::default(); let body = Self::parse_embedded_stmt(p, &mut stmt_opts)?; @@ -1100,7 +1149,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if p.lexer.is_keyword(T::TIn) { p.forbid_initializers(decls_ptr.slice(), "in", is_var)?; p.lexer.next_token()?; - let value = p.parse_expr(Level::Lowest)?; + let value = p.parse_expr_allow_in(Level::Lowest)?; p.lexer.expect(T::TCloseParen)?; let mut stmt_opts = ParseStatementOptions::default(); let body = Self::parse_embedded_stmt(p, &mut stmt_opts)?; @@ -1131,13 +1180,13 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if p.lexer.token != T::TSemicolon && !(p.lexer.token == T::TCloseParen && p.is_tolerant()) { - test = Some(p.parse_expr(Level::Lowest)?); + test = Some(p.parse_expr_allow_in(Level::Lowest)?); } p.lexer.expect(T::TSemicolon)?; if p.lexer.token != T::TCloseParen { - update = Some(p.parse_expr(Level::Lowest)?); + update = Some(p.parse_expr_allow_in(Level::Lowest)?); } p.lexer.expect(T::TCloseParen)?; @@ -1189,7 +1238,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> && p.lexer.token != T::TCloseBrace && p.lexer.token != T::TEndOfFile { - value = Some(p.parse_expr(Level::Lowest)?); + value = Some(p.parse_expr_allow_in(Level::Lowest)?); } p.latest_return_had_semicolon = p.lexer.token == T::TSemicolon; p.lexer.expect_or_insert_semicolon()?; @@ -1203,7 +1252,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if p.lexer.has_newline_before { return Self::t_throw_before_newline(p, loc); } - let expr = p.parse_expr(Level::Lowest)?; + let expr = p.parse_expr_allow_in(Level::Lowest)?; if !p.can_parse_semicolon() && p.is_tolerant() { Self::missing_semicolon_after_expr(p, &expr)?; } else { @@ -1298,15 +1347,16 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } } let recovers = p.is_tolerant() && !p.lexer.is_log_disabled; - let mut is_modifier_beside_decorators = - recovers && opts.ts_decorators.is_some() && p.is_at_modifier(false); + // At an `@`, `parseStatement` has not asked `isStartOfDeclaration`. + let is_after_decorators = recovers && opts.ts_decorators.is_some(); + let mut is_modifier_beside_decorators = is_after_decorators && p.is_at_modifier(false); p.push_statement_modifier(crate::sema::ts_syntax::Flags::EXPORT, loc); p.lexer.next()?; if p.lexer.token == T::TEscapedKeyword && recovers { Self::unescape_keyword_of_statement(p); } - if p.lexer.token == T::TAt && p.is_tolerant() { + if p.lexer.token == T::TAt && p.is_tolerant() && !Self::has_trailing_modifier(p, opts) { Self::more_decorators(p, opts)?; is_modifier_beside_decorators = recovers; } @@ -1425,6 +1475,20 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // "export type foo = ..." let type_range = p.lexer.range(); p.lexer.next_token()?; + // `canFollowExportModifier`: the `export` is no modifier, so + // `parseExportDeclaration` has taken the `type`. + if (is_after_decorators + || recovers && p.lexer.is_contextual_keyword(b"as")) + && !matches!(p.lexer.token, T::TOpenBrace | T::TAsterisk) + { + p.note_type_only_export(); + return Self::export_without_declaration( + p, + loc, + previous_export_keyword, + true, + ); + } // "export type\n{ foo }" and "export type\n* from 'bar'" are fine if p.lexer.has_newline_before && p.lexer.token != T::TOpenBrace @@ -1476,7 +1540,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } } - Self::export_without_declaration(p, loc, previous_export_keyword) + Self::export_without_declaration( + p, + loc, + previous_export_keyword, + is_after_decorators, + ) } T::TDefault => { @@ -1490,7 +1559,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.next()?; if p.lexer.token == T::TAt && p.is_tolerant() { - Self::more_decorators(p, opts)?; // `nextTokenCanFollowDefaultKeyword`: before a decorator `default` is a // modifier, and no expression follows. let (_, is_async) = Self::parse_modifiers(p, opts)?; @@ -1504,6 +1572,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> return Self::parse_declaration_worker(p, opts, is_async); } } + // Before `interface` it is a modifier too. + if recovers && p.lexer.is_contextual_keyword(b"interface") { + return Self::parse_declaration_worker(p, opts, false); + } // TypeScript decorators only work on class declarations // "@decorator export default class Foo {}" @@ -1961,23 +2033,36 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.esm_export_keyword = previous_export_keyword; p.parse_stmt(opts) } - _ => Self::export_without_declaration(p, loc, previous_export_keyword), + _ => Self::export_without_declaration( + p, + loc, + previous_export_keyword, + is_after_decorators, + ), } } /// Call at the token after the `export` at `loc` if nothing that can be exported starts there. Ordinary builds fail. /// Tolerant mode reports the error, consumes nothing more, and leaves the token to the next statement. + /// `is_export_declaration`: `parseDeclarationWorker` has taken the `export`, which is no modifier. #[cold] #[inline(never)] fn export_without_declaration( p: &mut Self, loc: bun_ast::Loc, previous_export_keyword: bun_ast::Range, + is_export_declaration: bool, ) -> Result { if !p.is_tolerant() || p.lexer.is_log_disabled { p.lexer.unexpected()?; return Err(crate::Error::SyntaxError); } + if is_export_declaration { + // `parseExportDeclaration`: `parseNamedExports` reports the missing "{". + let _ = p.parse_export_clause()?; + p.lexer.expect_or_insert_semicolon()?; + return Ok(p.s(S::TypeScript::default(), loc)); + } p.esm_export_keyword = previous_export_keyword; if p.is_start_of_declaration() { // `parseDeclarationWorker`: `export` is a modifier of a MissingDeclaration. @@ -1991,14 +2076,17 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(Stmt::empty()) } + /// `is_declaration`: `parseDeclarationWorker` has taken the keyword, so that no expression + /// starts here. #[inline] fn t_import( p: &mut Self, opts: &mut ParseStatementOptions<'a>, loc: bun_ast::Loc, + is_declaration: bool, ) -> Result { p.begin_module_syntax(opts); - let stmt = Self::parse_statement_after_import(p, opts, loc); + let stmt = Self::parse_statement_after_import(p, opts, loc, is_declaration); let kept = p.end_module_syntax(); Ok(p.keep_import(kept, stmt?, loc)) } @@ -2008,6 +2096,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p: &mut Self, opts: &mut ParseStatementOptions<'a>, loc: bun_ast::Loc, + is_declaration: bool, ) -> Result { let previous_import_keyword = p.esm_import_keyword; p.esm_import_keyword = p.lexer.range(); @@ -2035,7 +2124,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // "import.meta" // "import": no declaration either (`isStartOfStatement`). `parse_import_expr` says what is wrong with it. T::TOpenParen | T::TDot | T::TLessThan - if p.lexer.token != T::TLessThan || p.lexer.tolerant => + if !is_declaration && (p.lexer.token != T::TLessThan || p.lexer.tolerant) => { p.esm_import_keyword = previous_import_keyword; // this wasn't an esm import statement after all let mut expr = p.parse_import_expr(loc, Level::Lowest)?; @@ -2360,6 +2449,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> let range = self.lexer.range(); self.lexer.ts_error(range, 18016); self.lexer.next()?; + } else if self.lexer.token == T::TIdentifier + && self.is_tolerant() + && !self.is_identifier_in_context() + { + self.report_missing_identifier()?; } else { self.lexer.expect(T::TIdentifier)?; } @@ -2486,6 +2580,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> ) -> Result { let is_identifier = p.lexer.token == T::TIdentifier; let name = p.lexer.identifier; + let escaped_name = if p.is_tolerant() && is_identifier { + p.lexer.escaped_word() + } else { + None + }; if p.is_tolerant() && is_identifier && Self::IS_TYPESCRIPT_ENABLED { if let Some(stmt) = Self::parse_declaration_after_modifiers(p, opts)? { return Ok(stmt); @@ -2555,9 +2654,10 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if let Some(stmt) = Self::parse_stmt_fallthrough_ts_keyword(p, opts, loc, ts_stmt)? { - if p.is_tolerant() { - let end = p.noted_end(expr.loc); - Self::ts_keyword_was_taken(p, loc, end, name, ts_stmt); + // `global` is parsed as a name + // (`parseAmbientExternalModuleDeclaration`). + if ts_stmt != js_lexer::TypescriptStmtKeyword::TsStmtGlobal { + p.lexer.keyword_was_taken(escaped_name); } return Ok(stmt); } @@ -2695,29 +2795,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> Ok(()) } - /// The word from `loc` to `end`, which spells `name`, was treated as the keyword of the - /// statement just parsed. `nextToken` reports a keyword written with an escape. `global` is - /// parsed as a name (`parseAmbientExternalModuleDeclaration`). - #[cold] - #[inline(never)] - fn ts_keyword_was_taken( - p: &mut Self, - loc: bun_ast::Loc, - end: Option, - name: &[u8], - ts_stmt: js_lexer::TypescriptStmtKeyword, - ) { - if ts_stmt != js_lexer::TypescriptStmtKeyword::TsStmtGlobal - && !p.source.contents()[loc.to_usize()..].starts_with(name) - { - // It precedes all errors reported for the rest of the statement. - let last = p.lexer.prev_error_loc; - let len = end.map_or(0, |end| end.start - loc.start); - p.lexer.ts_error(bun_ast::Range { loc, len }, 1260); - p.lexer.prev_error_loc = last; - } - } - /// A reserved word written with an escape, at the start of a statement. It is treated as the /// word it spells, and `nextToken` reports the escape when the word is consumed. #[cold] @@ -2964,18 +3041,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> && !p.lexer.is_log_disabled && p.lexer.is_contextual_keyword(b"type") { - let type_keyword_loc = p.lexer.loc(); - p.lexer.next_token()?; - if p.lexer.has_newline_before { - let range = p.lexer.range(); - p.lexer.ts_error(range, 1142); - } - let mut stmt_opts = ParseStatementOptions { - scope: opts.scope, - ..Default::default() - }; - p.skip_type_script_type_stmt(&mut stmt_opts, type_keyword_loc)?; - return Ok(Some(p.type_script_statement(loc))); + return Self::parse_type_alias_declaration(p, opts.scope, loc).map(Some); } // "declare const x: any" @@ -3121,7 +3187,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> T::TSwitch => Self::t_switch(self, opts, loc), T::TTry => Self::t_try(self, opts, loc), T::TFor => Self::t_for(self, opts, loc), - T::TImport => Self::t_import(self, opts, loc), + T::TImport => Self::t_import(self, opts, loc, false), T::TBreak => Self::t_break(self, opts, loc), T::TContinue => Self::t_continue(self, opts, loc), T::TReturn => Self::t_return(self, opts, loc), diff --git a/src/js_parser/parse/parse_suffix.rs b/src/js_parser/parse/parse_suffix.rs index 104507864917..d807f07b5c5e 100644 --- a/src/js_parser/parse/parse_suffix.rs +++ b/src/js_parser/parse/parse_suffix.rs @@ -279,7 +279,19 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } } - match p.lexer.token { + // `tryParseTypeArgumentsInExpression`. If there are none, the name is missing at the "<". + let less_than = p.lexer.loc(); + let has_type_arguments = p.is_tolerant() + && matches!(p.lexer.token, T::TLessThan | T::TLessThanLessThan) + && !p.lexer.is_javascript_file() + && p.try_skip_type_script_type_arguments_in_chain_with_backtracking(true)?; + let token = if has_type_arguments { + T::TLessThan + } else { + p.lexer.token + }; + + match token { T::TOpenBracket => { // "a?.[b]" let after_bracket = bun_ast::usize2loc(p.lexer.end); @@ -334,14 +346,25 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> loc, ); } - T::TLessThan | T::TLessThanLessThan if !p.lexer.is_javascript_file() => { + T::TLessThan | T::TLessThanLessThan + if !p.lexer.is_javascript_file() && (has_type_arguments || !p.is_tolerant()) => + 'call: { // "a?.()" if !Self::IS_TYPESCRIPT_ENABLED { p.lexer.expected(T::TIdentifier)?; return Err(crate::Error::SyntaxError); } - let _ = p.skip_type_script_type_arguments::()?; + if !has_type_arguments { + let _ = p.skip_type_script_type_arguments::()?; + } else if matches!( + p.lexer.token, + T::TNoSubstitutionTemplateLiteral | T::TTemplateHead + ) { + // "a?.`b`": the suffix that parses the template takes the type arguments. + p.note_type_arguments(left, less_than); + break 'call; + } let type_arguments = p.saved_type_arguments(); if p.lexer.token != T::TOpenParen { p.lexer.expected(T::TOpenParen)?; @@ -455,7 +478,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> fn sfx_t_no_substitution_template_literal( p: &mut Self, _level: Level, - _optional_chain: &mut Option, + optional_chain: &mut Option, old_optional_chain: Option, left: &mut Expr, ) -> CResult { @@ -466,6 +489,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> p.lexer.range(), b"Template literals cannot have an optional chain as a tag", ); + Self::sfx_chain_after_tagged_template(p, optional_chain, old_optional_chain); } // `hasCorrectArity`: a call with an unterminated template is incomplete. let is_incomplete = p.is_tolerant() && p.lexer.unterminated_at == p.lexer.start; @@ -491,7 +515,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> fn sfx_t_template_head( p: &mut Self, _level: Level, - _optional_chain: &mut Option, + optional_chain: &mut Option, old_optional_chain: Option, left: &mut Expr, ) -> CResult { @@ -510,6 +534,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if p.is_tolerant() && Self::sfx_tag_is_optional_chain(p, old_optional_chain, left) { // `checkGrammarTaggedTemplateChain`: said of `node.Template`. p.lexer.ts_grammar_error(p.lexer.range_from(backtick), 1358); + Self::sfx_chain_after_tagged_template(p, optional_chain, old_optional_chain); } // `hasCorrectArity`: a call with a template whose last literal is missing or unterminated is incomplete. let is_incomplete = p.is_tolerant() && p.lexer.unterminated_at == tail_loc.start as usize; @@ -1198,6 +1223,19 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> chain.is_some() && !(p.is_tolerant() && p.last_cast(left) == Some(Mark::NonNull)) } + /// `parseTaggedTemplateRest`: a tagged template whose tag has `NodeFlagsOptionalChain` has it + /// too, so that `tryReparseOptionalChain` keeps what follows it in `chain`. + #[inline] + fn sfx_chain_after_tagged_template( + p: &Self, + optional_chain: &mut Option, + chain: Option, + ) { + if p.is_tolerant() { + *optional_chain = chain; + } + } + fn sfx_t_less_than( p: &mut Self, level: Level, @@ -1205,11 +1243,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> old_optional_chain: Option, left: &mut Expr, ) -> CResult { - // `Scan`: in a file with JSX " if Self::IS_TYPESCRIPT_ENABLED // `tryParseTypeArgumentsInExpression` && !p.lexer.is_javascript_file() + // Only `parseMemberExpressionRest` and `parseCallExpressionRest` call it. + && !(p.is_tolerant() && Self::sfx_is_not_left_hand_side(p, left)) && p.try_skip_type_script_type_arguments_in_chain_with_backtracking(is_optional_chain)? { *optional_chain = Self::sfx_chain_after_type_arguments(p, old_optional_chain); @@ -1338,6 +1373,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if Self::IS_TYPESCRIPT_ENABLED && !p.lexer.is_javascript_file() && !is_jsx_element + && !(p.is_tolerant() && Self::sfx_is_not_left_hand_side(p, left)) && p.try_skip_type_script_type_arguments_in_chain_with_backtracking(is_optional_chain)? { *optional_chain = Self::sfx_chain_after_type_arguments(p, old_optional_chain); @@ -1823,6 +1859,30 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> ) } + /// Whether the syntax of `left` ends with a closing token. At a token that is forbidden as a + /// suffix, that token is missing, and the expression the suffix is forbidden after is inside + /// `left`: `parseMemberExpressionRest` and `parseCallExpressionRest` go on after `left`. + #[cold] + #[inline(never)] + fn sfx_ends_with_closing_token(p: &Self, left: &Expr) -> bool { + if let Some(kind) = p.last_cast(left) { + return kind == Mark::Paren; + } + match &left.data { + ExprData::EIndex(access) => { + !matches!(access.index.data, ExprData::EPrivateIdentifier(_)) + } + ExprData::EObject(_) + | ExprData::EArray(_) + | ExprData::ETemplate(_) + | ExprData::EClass(_) + | ExprData::ECall(_) + | ExprData::ENew(_) + | ExprData::EImport(_) => true, + _ => false, + } + } + fn sfx_t_in(p: &mut Self, level: Level, left: &mut Expr) -> CResult { if level.gte(Level::Compare) || !p.allow_in { return Ok(Continuation::Done); @@ -1935,6 +1995,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // An operand that is missing at this token starts another expression, which // the operator continues (`parseBinaryExpressionRest`). && !(matches!(left.data, ExprData::EMissing(_)) && p.is_tolerant()) + && !(p.is_tolerant() && Self::sfx_ends_with_closing_token(p, left)) { break; } diff --git a/src/js_parser/parse/parse_typescript.rs b/src/js_parser/parse/parse_typescript.rs index 3cfc39200396..0f1c9d204216 100644 --- a/src/js_parser/parse/parse_typescript.rs +++ b/src/js_parser/parse/parse_typescript.rs @@ -781,13 +781,13 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> T::TPrivateIdentifier => value.name = js_ast::StoreStr::new(p.lexer.identifier), T::TOpenBracket => { p.lexer.next()?; - // `[("a")]`: a `ParenthesizedExpression` is no literal. - let is_literal = p.lexer.token != T::TOpenParen; let old_allow_in = core::mem::replace(&mut p.allow_in, true); let name = p.parse_expr(Level::Lowest); p.allow_in = old_allow_in; // `["a"]` and `[1]` are names like `"a"` and `1`. Any other expression leaves the member without a name. let name = name?; + // `IsStringOrNumericLiteralLike`: not `("a")`, `"a" as const`, `"a"!`, `"a"`. + let is_literal = p.last_cast(&name).is_none(); match name.data { js_ast::ExprData::EString(string) if is_literal && !string.is_utf16 => { value.name = string.data; @@ -922,7 +922,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> // Parse the initializer if p.lexer.token == T::TEquals { p.lexer.next()?; - value.value = Some(p.parse_expr(Level::Comma)?); + value.value = Some(p.parse_expr_allow_in(Level::Comma)?); } let value_name = value.name; diff --git a/src/js_parser/sema/clone_types.rs b/src/js_parser/sema/clone_types.rs index 146c3c1bd224..6cbd8c4c94ba 100644 --- a/src/js_parser/sema/clone_types.rs +++ b/src/js_parser/sema/clone_types.rs @@ -619,16 +619,19 @@ impl Builder<'_> { _ => self.file.error(DiagnosticKind::Grammar, at, 0, code), } } - // `checkVariableLikeDeclaration`: reported regardless of other errors in the file. - if kind == MemberKind::Property && matches!(key, ts::PropertyKey::BigInt) { - self.file.error(DiagnosticKind::Checker, pos(loc), 0, 1539); - } let is_number = matches!(key, ts::PropertyKey::Number(_)); let mut key = self.key(key); // `getDeclarationName`: a private name outside a class declares nothing. if self.classes_around == 0 && matches!(key, PropKey::Private(_)) { key = PropKey::None; } + // `declareSymbolEx`: `isDefaultExport && parent != nil` + if matches!(key, PropKey::Name(_)) + && !modifiers.is_empty() + && self.file.find_modifier(modifiers, Flags::DEFAULT).is_some() + { + key = PropKey::Name(known::default); + } if func.is_some() { self.file[func].name = key.name().unwrap_or(Atom::NONE); self.file[func].start = pos(start); @@ -775,7 +778,11 @@ impl Builder<'_> { | TypeNodeKind::BigIntLit { .. } | TypeNodeKind::BoolLit(_) | TypeNodeKind::UniqueSymbol => {} - TypeNodeKind::Heritage(e) => id!(e, exprs), + TypeNodeKind::Heritage { expr, args } => { + id!(expr, exprs); + run!(args, ids); + lists.push(*args); + } TypeNodeKind::NumberLit(number) => *number = number.wrapping_add(moved.numbers), TypeNodeKind::Ref { name, args } | TypeNodeKind::Import { name, args, .. } => { run!(name, names); diff --git a/src/js_parser/sema/comments.rs b/src/js_parser/sema/comments.rs index 5fa45f008cc6..cc58cdcb2f96 100644 --- a/src/js_parser/sema/comments.rs +++ b/src/js_parser/sema/comments.rs @@ -21,6 +21,38 @@ pub(crate) mod flags { pub(crate) const JSDOC_LIKE: u8 = 1 << 1; /// `KindSingleLineCommentTrivia` pub(crate) const SINGLE_LINE: u8 = 1 << 2; + /// `TokenFlagsPrecedingJSDocWithSeeOrLink` + pub(crate) const SEE_OR_LINK: u8 = 1 << 3; + /// No `@augments` or `@extends` tag is in a comment without it. + pub(crate) const AUGMENTS: u8 = 1 << 4; + /// No `@param`, `@arg` or `@argument` tag is in a comment without it. + pub(crate) const PARAM: u8 = 1 << 5; +} + +/// `scanJSDocCommentForTags`, which looks for `@see` and `@link`, and for the tags that the checker +/// reads in a TypeScript file. +fn scan_jsdoc_comment_for_tags(mut comment: &[u8]) -> u8 { + let mut found = 0; + while let Some(at) = bun_core::strings::index_of_char_usize(comment, b'@') { + comment = &comment[at + 1..]; + let len = comment + .iter() + .take_while(|c| c.is_ascii_alphabetic()) + .count(); + found |= match (&comment[..len], comment.get(len)) { + // `ScanJSDocToken` decodes an escape in a name. + (_, Some(b'\\')) => flags::AUGMENTS | flags::PARAM, + // `hasJSDocTag` + ( + b"see" | b"link" | b"linkcode" | b"linkplain", + None | Some(b' ' | b'\t' | b'\n' | b'\r' | b'}' | b'*'), + ) => flags::SEE_OR_LINK, + (b"augments" | b"extends", _) => flags::AUGMENTS, + (b"param" | b"arg" | b"argument", _) => flags::PARAM, + _ => 0, + }; + } + found } impl Lexer<'_> { @@ -40,7 +72,7 @@ impl Lexer<'_> { } let comment = &text[self.start..self.end]; if super::jsdoc::is_jsdoc_like(comment) { - reported |= flags::JSDOC_LIKE; + reported |= flags::JSDOC_LIKE | scan_jsdoc_comment_for_tags(comment); } if comment.starts_with(b"//") { reported |= flags::SINGLE_LINE; @@ -48,6 +80,31 @@ impl Lexer<'_> { self.comment_flags.push(reported); } + /// The JSDoc comments of a TypeScript file that have to be parsed are those with one of the + /// returned `flags`. Only the checker reads their tags, in two functions. + pub(crate) fn jsdoc_read_by_checker(&self, is_declaration_file: bool) -> u8 { + // JSON + if self.is_javascript_file() { + return 0; + } + let flags_of_all = self.comment_flags.iter().fold(0, |all, &it| all | it); + // `checkUnmatchedJSDocParameters` reports nothing in TypeScript, but for a function with a + // `@param` tag `containsArgumentsReference` resolves the identifiers named `arguments` in + // the body. `getAllJSDocTags` needs to know of every comment whether it has tags. + if flags_of_all & flags::PARAM != 0 + && !is_declaration_file + && (bun_core::strings::contains(self.contents, b"arguments") + || bun_core::strings::contains(self.contents, b"\\u")) + { + return flags::JSDOC_LIKE; + } + // `checkGrammarClassDeclarationHeritageClauses`, which reads `EagerJSDoc`. + if flags_of_all & flags::AUGMENTS != 0 && flags_of_all & flags::SEE_OR_LINK != 0 { + return flags::AUGMENTS; + } + 0 + } + /// `processCommentDirective` for the comment just scanned, from `start` to `end`. `multiline`: /// a `/* */` comment, of which only the last line is considered (`last_line_start`). #[inline(never)] diff --git a/src/js_parser/sema/jsdoc.rs b/src/js_parser/sema/jsdoc.rs index 1f3401894582..75112d5de31e 100644 --- a/src/js_parser/sema/jsdoc.rs +++ b/src/js_parser/sema/jsdoc.rs @@ -163,6 +163,8 @@ pub(crate) struct Import { pub(crate) clause_end: u32, pub(crate) namespace_start: u32, pub(crate) named: Vec, + /// `importClause.NamedBindings` is a `NamedImports`. + pub(crate) has_named_imports: bool, /// The module specifier and its position. `None` if it is not a string. pub(crate) specifier: Option<(StoreStr, u32)>, pub(crate) module: Option, @@ -221,6 +223,8 @@ pub(crate) struct Comments { pub(crate) list: Vec, /// The HIR nodes of the types in them. pub(crate) types: super::clone_types::CommentTypes, + /// `File::jsdoc_asterisks` + pub(crate) asterisks: Vec, } impl Comments { @@ -250,11 +254,13 @@ fn is_object_or_object_array(file: &bun_sema::hir::FileBuilder, ty: ts::TypeId) } } -/// Parses every JSDoc comment recorded by the lexer of `p`. `syntax` is the type syntax the parser -/// saved for the file. The types in the comments become nodes of a separate HIR. +/// Parses every comment recorded by the lexer of `p` that has one of the `comments::flags` in +/// `wanted`. `syntax` is the type syntax the parser saved for the file. The types in the comments +/// become nodes of a separate HIR. pub(crate) fn read_comments<'a>( p: &mut P<'a, true, false, true>, mut syntax: TypeSyntax<'a>, + wanted: u8, ) -> (TypeSyntax<'a>, Comments) { let mut comments = Comments::default(); if !syntax.save_types || !p.is_tolerant() { @@ -265,17 +271,20 @@ pub(crate) fn read_comments<'a>( let flags = core::mem::take(&mut p.lexer.comment_flags); let file = core::mem::take(&mut syntax.b.file); let pending = core::mem::take(&mut syntax.b.pending); + let function_contexts = core::mem::take(&mut syntax.function_contexts); p.type_syntax = Some(Box::new(syntax)); + // `parseJSDocComment` leaves `statementHasAwaitIdentifier` as it finds it. + p.lexer.await_name_seen = false; // `PCJSDocComment`: like `PCJsxChildren`, any token is an element of it, so list error recovery // never skips a token. let outer_contexts = core::mem::replace( &mut p.lexer.list_contexts, 1 << ListKind::JsxChildren as u32, ); - for range in &ranges { + for (range, &reported) in ranges.iter().zip(&flags) { let (start, end) = (range.loc.to_usize(), range.end_i().min(source.len())); let comment = &source[start.min(end)..end]; - if !is_jsdoc_like(comment) + if reported & wanted == 0 || !comment.ends_with(b"*/") || !bun_core::strings::contains_char(comment, b'@') { @@ -288,13 +297,36 @@ pub(crate) fn read_comments<'a>( { continue; } + // `withJSDoc`: in the [Await] and [Yield] contexts of its place. Only the names of an + // `@import` tag depend on them: types are parsed outside both. + let innermost = + if function_contexts.is_empty() || !bun_core::strings::contains(comment, b"@import") { + None + } else { + let around = function_contexts + .iter() + .filter(|it| (it.start.to_usize()..it.end.to_usize()).contains(&start)); + around.max_by_key(|it| it.start.start) + }; + let data = &mut p.fn_or_arrow_data_parse; + let outer = (data.allow_await, data.allow_yield, data.is_top_level); + if let Some(innermost) = innermost { + data.allow_await = innermost.allow_await; + data.allow_yield = innermost.allow_yield; + data.is_top_level = false; + } comments.list.push(Reader::read(p, source, start, end)); + let data = &mut p.fn_or_arrow_data_parse; + (data.allow_await, data.allow_yield, data.is_top_level) = outer; } p.lexer.contents = source; p.lexer.all_comments = ranges; p.lexer.comment_flags = flags; p.lexer.list_contexts = outer_contexts; p.lexer.skips_jsdoc_asterisks = false; + comments.asterisks = core::mem::take(&mut p.lexer.jsdoc_asterisks); + comments.asterisks.sort_unstable(); + comments.asterisks.dedup(); let mut syntax = *p.type_syntax.take().expect("set above"); comments.types.file = core::mem::replace(&mut syntax.b.file, file); comments.types.pending = core::mem::replace(&mut syntax.b.pending, pending); @@ -495,8 +527,7 @@ impl<'p, 'a> Reader<'p, 'a> { .drain(before.0..) .filter(|msg| msg.kind == bun_ast::Kind::Err); let diagnostics = errors.filter_map(|msg| { - // `ScanJSDocToken` does not scan ` Reader<'p, 'a> { self.leave_lexer(result); } + /// `isIdentifier`, of the word `word`. The top level is outside the [Await] context. + fn is_identifier(&self, word: &[u8]) -> bool { + let data = &self.p.fn_or_arrow_data_parse; + let off = crate::AwaitOrYield::AllowIdent; + crate::lexer::keyword(word).is_none() + && !(word == b"await" && data.allow_await != off && !data.is_top_level) + && !(word == b"yield" && data.allow_yield != off) + } + /// `parseImportTag`, starting at the token after the tag name. fn read_import(&mut self) -> Import { // Either only whitespace remains in the comment (`skipWhitespaceOrAsterisk` does not consume it), or `ScanJSDocToken` returned - // `KindUnknown`, for example for a quote or a slash. `parseModuleSpecifier` reports TS1109 without consuming the token. + // `KindUnknown`, for example for a quote or a slash, or a token of its own: `#a` is no private name and a backtick opens no + // template. `parseModuleSpecifier` reports TS1109 without consuming the token. let cannot_start_expression = matches!( self.token, - Token::Whitespace | Token::NewLine | Token::Unknown + Token::Whitespace | Token::NewLine | Token::Unknown | Token::Hash | Token::Backtick ); if !self.is_in_lexer && cannot_start_expression { self.error_at_token(1109); @@ -949,7 +990,7 @@ impl<'p, 'a> Reader<'p, 'a> { }; // `isIdentifier`, `parseIdentifier`: the token after the tag name is one of // `ScanJSDocToken`, whose words can contain `-`. - if self.token == Token::Word && crate::lexer::keyword(self.token_value()).is_none() { + if self.token == Token::Word && self.is_identifier(self.token_value()) { import.default = Some(self.name_at_word()); self.next_token(); } @@ -1002,6 +1043,7 @@ impl<'p, 'a> Reader<'p, 'a> { } } else { // `parseNamedImports` + import.has_named_imports = true; p.parse_import_clause()?; let syntax = p.type_syntax_mut(); let specifiers = syntax.module_syntax.last().and_then(|kept| kept.specifiers); @@ -1130,6 +1172,12 @@ impl<'p, 'a> Reader<'p, 'a> { state = State::SavingComments; indent += self.token_len(); } + Token::OpenBrace if !in_fenced_code_block => { + state = State::SavingComments; + if !self.link() { + indent += self.token_len(); + } + } Token::At | Token::OpenBrace => { state = State::saving(in_fenced_code_block); indent += self.token_len(); @@ -1281,6 +1329,18 @@ impl<'p, 'a> Reader<'p, 'a> { indent += self.token_len(); is_text = false; } + Token::OpenBrace if !in_fenced_code_block => { + state = State::SavingComments; + let start = self.start; + if self.link() { + is_text = false; + has_text = true; + if self.saves_comment_text { + self.comment_text + .extend_from_slice(&self.text[start..self.end]); + } + } + } Token::At | Token::OpenBrace => state = State::saving(in_fenced_code_block), Token::Backtick => { backticks += 1; @@ -1328,6 +1388,65 @@ impl<'p, 'a> Reader<'p, 'a> { && matches!(self.token_value(), b"link" | b"linkcode" | b"linkplain") } + /// `parseJSDocLink`, up to the `}`, the line break or the end that closes it. False: there is + /// none, and nothing is consumed. + fn link(&mut self) -> bool { + let mark = self.mark(); + if !self.is_at_link() { + self.rewind(&mark); + return false; + } + self.next_jsdoc(); + self.skip_whitespace(); + self.link_name(); + while !matches!( + self.token, + Token::CloseBrace | Token::NewLine | Token::EndOfFile + ) { + self.next_jsdoc(); + } + true + } + + /// `parseJSDocLinkName` + fn link_name(&mut self) { + if self.token != Token::Word { + return; + } + self.link_identifier(true); + while self.eat(Token::Dot) { + // `createMissingIdentifier` + if !self.is_at_private_identifier() { + self.link_identifier(true); + } + } + while self.is_at_private_identifier() { + // `ReScanHashToken` + self.reset_pos(self.start + 1); + self.next_jsdoc(); + self.link_identifier(false); + } + } + + /// `parseIdentifierName`, or `parseIdentifier` unless `allows_reserved_words`. A missing name is + /// reported, and the token is not consumed. + fn link_identifier(&mut self, allows_reserved_words: bool) { + let is_word = self.token == Token::Word && !self.is_at_private_identifier(); + let is_reserved_word = is_word && crate::lexer::keyword(self.token_value()).is_some(); + if is_word && (allows_reserved_words || !is_reserved_word) { + self.next_token(); + } else if self.token == Token::EndOfFile { + self.error(self.full_start(), 0, 1003); + } else { + self.error_at_token(if is_reserved_word { 1359 } else { 1003 }); + } + } + + /// `KindPrivateIdentifier`, which only `Scan` returns. + fn is_at_private_identifier(&self) -> bool { + self.is_in_lexer && self.p.lexer.token == T::TPrivateIdentifier + } + // ───────────────────────────── tags ───────────────────────────── /// `parseTag` diff --git a/src/js_parser/sema/keep.rs b/src/js_parser/sema/keep.rs index 41dcee0e4c73..2b786adc9ebd 100644 --- a/src/js_parser/sema/keep.rs +++ b/src/js_parser/sema/keep.rs @@ -15,7 +15,7 @@ use crate::sema::ts_syntax::{ StatementData, StatementId, TupleElement, TypeAlias, TypeId, TypeParam, TypeParams, Types, }; use bun_ast::{Expr, Loc, StoreStr}; -use bun_sema::hir::{DiagnosticKind, JSDocTypeKind, PatKind, TypeNode, TypeNodeKind}; +use bun_sema::hir::{DiagnosticKind, ExprId, JSDocTypeKind, PatKind, TypeNode, TypeNodeKind}; use super::TypeSyntax; use crate::lexer::{PropertyModifierKeyword, T}; @@ -59,13 +59,14 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> #[inline] pub(crate) fn clear_last_type(&mut self) { - self.type_syntax_mut().last_type = TypeId::NONE; + self.type_syntax_mut().set_last_type(TypeId::NONE); } #[inline] pub(crate) fn emit_type(&mut self, kind: TypeNodeKind, pos: u32) { let syntax = self.type_syntax_mut(); - syntax.last_type = syntax.b.file.ty(kind, pos, 0); + let ty = syntax.b.file.ty(kind, pos, 0); + syntax.set_last_type(ty); } /// `finishNode` for the last parsed type, unless it is already finished: it ends at the end of @@ -334,7 +335,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if syntax.last_type.is_none() || syntax.last_type.idx() + 1 != syntax.b.file.types.len() { return None; } - syntax.last_type = TypeId::NONE; + syntax.set_last_type(TypeId::NONE); syntax.b.file.types.pop() } @@ -521,7 +522,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> if syntax.last_type.is_some() { // `checkNamedTupleMember`. The element is required (`getTupleElementFlags`). syntax.b.file.error(DiagnosticKind::Grammar, pos, end, 5087); - syntax.last_type = syntax.b.rest_element_type(syntax.last_type); + let ty = syntax.b.rest_element_type(syntax.last_type); + syntax.set_last_type(ty); } } @@ -535,10 +537,21 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.emit_type(union, pos); } - /// `interface I extends expression`, `class C implements expression`. The checker reports it - /// (2499, 2500). - pub(crate) fn emit_heritage_expression(&mut self, expression: Expr, pos: u32) { - self.emit_type(TypeNodeKind::Error, pos); + /// `interface I extends expression`, `class C implements expression`. The checker + /// reports it (2499, 2500). `has_arguments`: type arguments follow the expression, and are the + /// last ones parsed. + pub(crate) fn emit_heritage_expression( + &mut self, + expression: Expr, + has_arguments: bool, + pos: u32, + ) { + let args = match has_arguments { + true => self.take_saved_type_argument_list(), + false => Types::EMPTY, + }; + let expr = ExprId::NONE; + self.emit_type(TypeNodeKind::Heritage { expr, args }, pos); let node = self.last_type(); let part = super::clone_types::PendingPart::HeritageExpression(node, expression); self.type_syntax_mut().b.pending.push(part); @@ -619,7 +632,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } } - /// The current token as a property key, if it is an identifier, keyword, string or number. + /// The current token as a property key, if it is an identifier, keyword, string, number or + /// private name. pub(crate) fn simple_property_key(&mut self) -> PropertyKey { match self.lexer.token { T::TStringLiteral | T::TNoSubstitutionTemplateLiteral => self @@ -627,6 +641,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> .map_or(PropertyKey::None, PropertyKey::Name), T::TNumericLiteral => PropertyKey::Number(self.lexer.number), T::TBigIntegerLiteral => PropertyKey::BigInt, + T::TPrivateIdentifier => PropertyKey::Private(StoreStr::new(self.lexer.identifier)), _ if self.lexer.is_identifier_or_keyword() => PropertyKey::Name(self.token_text()), _ => PropertyKey::None, } @@ -725,14 +740,20 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> pub(crate) fn read_member_word(&mut self) -> MemberWord { MemberWord { token: self.lexer.token, - key: match self.lexer.token { - T::TPrivateIdentifier => PropertyKey::Private(StoreStr::new(self.lexer.identifier)), - _ => self.simple_property_key(), - }, + key: self.simple_property_key(), pos: self.token_start(), } } + /// `createMissingIdentifier`, at a token that is not the name of a member. + pub(crate) fn missing_member_word(&self) -> MemberWord { + MemberWord { + token: T::TIdentifier, + key: PropertyKey::Name(StoreStr::EMPTY), + pos: self.lexer.token_full_start as u32, + } + } + /// Adds a finished member to the object type being built. pub(crate) fn finish_type_member( &mut self, @@ -754,12 +775,17 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> .filter(|accessor| kept.is_complete && accessor.signature.is_some()) { let end = self.lexer.full_start(); - self.type_syntax_mut().b.add_signature_body( + let syntax = self.type_syntax_mut(); + // The modifiers of every declaration being parsed. + let mut around = syntax.statement_modifiers.iter(); + let is_ambient = around.any(|modifier| modifier.flag == Flags::AMBIENT); + syntax.b.add_signature_body( accessor.signature, FunctionBody { loc: body.loc, end, stmts: body.stmts, + is_ambient, }, ); } @@ -781,8 +807,17 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } impl TypeSyntax<'_> { - /// `typeHasArrowFunctionBlockingParseError`, for the last parsed type. + #[inline] + pub(crate) fn set_last_type(&mut self, ty: TypeId) { + self.last_type = ty; + self.last_type_lacks_parameters = false; + } + + /// `typeHasArrowFunctionBlockingParseError`, for the last parsed type. A type in parentheses has no node of its own. pub(crate) fn last_type_blocks_arrow_function(&self) -> bool { + if self.last_type_lacks_parameters { + return true; + } let file = &self.b.file; let mut ty = self.last_type; while ty.is_some() { @@ -812,7 +847,7 @@ impl TypeSyntax<'_> { file.names.truncate(name.start as usize); } } - self.last_type = TypeId::NONE; + self.set_last_type(TypeId::NONE); } /// Pops the list that starts at `from` in `type_stack`. `None` if any item is missing. @@ -851,7 +886,7 @@ impl TypeSyntax<'_> { b.file.entity_name([(first, pos)].into_iter()) } _ => { - self.last_type = TypeId::NONE; + self.set_last_type(TypeId::NONE); return; } }; @@ -884,11 +919,11 @@ impl TypeSyntax<'_> { fn attach_type_args(&mut self, reference: Option, has_arguments: bool) { let Some(mut node) = reference else { if has_arguments { - self.last_type = TypeId::NONE; + self.set_last_type(TypeId::NONE); } return; }; - self.last_type = TypeId::NONE; + self.set_last_type(TypeId::NONE); if has_arguments { node.end = 0; match (&mut node.kind, self.last_type_args.take()) { @@ -901,32 +936,22 @@ impl TypeSyntax<'_> { _ => return, } } - self.last_type = self.b.file.add_type_node(node); + let ty = self.b.file.add_type_node(node); + self.set_last_type(ty); } /// Emits `typeof a.b.c` at `pos`. The names are in `name_stack` starting at `names_base`. fn emit_typeof_type(&mut self, names_base: usize, has_arguments: bool, pos: u32) { - let name_stack = &mut self.name_stack; - // `typeof a.`: the part before the last dot is still resolved (`parseRightSideOfDot`). - // `typeof` without a name has a single, missing name (`parseEntityName`). Any other missing - // name makes the type unusable. - let required = (name_stack.len() - names_base).saturating_sub(1); - let is_complete = name_stack[names_base..] - .iter() - .take(required) - .all(|name| !name.text.is_empty()); - let names: smallvec::SmallVec<[Name; 4]> = name_stack.drain(names_base..).collect(); - self.last_type = TypeId::NONE; - if !is_complete { - return; - } + let names: smallvec::SmallVec<[Name; 4]> = self.name_stack.drain(names_base..).collect(); + self.set_last_type(TypeId::NONE); let args = match (has_arguments, self.last_type_args.take()) { (false, _) => Types::EMPTY, (true, Some(args)) => args, (true, None) => return, }; let data = self.b.add_typeof(&names, args, has_arguments); - self.last_type = self.b.file.ty(data, pos, 0); + let ty = self.b.file.ty(data, pos, 0); + self.set_last_type(ty); } /// `GetResolutionModeOverride`, from the nodes of the object type parsed last. @@ -1387,7 +1412,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> /// `ModifierToFlag`, of the modifier keyword at the current token (`is_modifier_kind`). pub(crate) fn modifier_flag_here(&self) -> Flags { - match self.lexer.token { + match self.token() { T::TConst => Flags::CONST, T::TDefault => Flags::DEFAULT, T::TExport => Flags::EXPORT, @@ -1407,7 +1432,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> } } - /// `modifiers` are those of the parameter whose name has the `loc` `loc`. + /// `modifiers` are those of the parameter whose name has the `loc` `loc`, or the keywords among + /// those of the class expression whose `class` has it. pub(crate) fn note_parameter_modifiers(&mut self, loc: &mut Loc, modifiers: &[Modifier]) { if self.should_save_types() && !modifiers.is_empty() { let list = self.type_syntax_mut().b.ts.add_modifiers(modifiers); diff --git a/src/js_parser/sema/lower.rs b/src/js_parser/sema/lower.rs index d018f5a6a1f0..f5813da1f428 100644 --- a/src/js_parser/sema/lower.rs +++ b/src/js_parser/sema/lower.rs @@ -32,7 +32,7 @@ pub(crate) struct Lower<'p, 'a> { /// `TokenFullStart` of the end of the file. end_of_file_full_start: u32, stack_check: bun_core::StackCheck, - /// The JSDoc comments of a JavaScript file. None for TypeScript. + /// The JSDoc comments of a JavaScript file. In TypeScript, `Lexer::jsdoc_read_by_checker`. pub(super) jsdoc: std::rc::Rc, /// Which of them are attached to a node. pub(super) jsdoc_is_attached: Vec, @@ -57,6 +57,9 @@ pub(crate) struct Lower<'p, 'a> { /// `NodeFlagsAmbient`: the node being lowered is in a declaration file or inside a `declare` /// declaration. is_ambient: bool, + /// `checkGrammarModuleElementContext`, for a statement of the list being lowered: it is the + /// list of the file. + pub(super) is_in_appropriate_context: bool, } impl<'p, 'a> Lower<'p, 'a> { @@ -67,9 +70,13 @@ impl<'p, 'a> Lower<'p, 'a> { is_declaration_file: bool, ) -> hir::FileBuilder { let end_of_file_full_start = p.lexer.token_full_start as u32; - // `withJSDoc`: tags are only processed in JavaScript files. - let (mut syntax, jsdoc) = if syntax.has_jsdoc { - super::jsdoc::read_comments(p, syntax) + let wanted = if syntax.has_jsdoc { + super::comments::flags::JSDOC_LIKE + } else { + p.lexer.jsdoc_read_by_checker(is_declaration_file) + }; + let (mut syntax, jsdoc) = if wanted != 0 { + super::jsdoc::read_comments(p, syntax, wanted) } else { (syntax, Comments::default()) }; @@ -98,6 +105,7 @@ impl<'p, 'a> Lower<'p, 'a> { full_signatures: Default::default(), documented_functions: Default::default(), is_ambient: is_declaration_file, + is_in_appropriate_context: true, }; this.b.file.source_len = source_len as u32; this.b.file.kind = if is_declaration_file { @@ -172,7 +180,10 @@ impl<'p, 'a> Lower<'p, 'a> { PendingPart::FunctionBody(func, body) => { let open = self.pos_of(body.loc); self.b.file.body_starts.push((func, open)); + let was_ambient = self.is_ambient; + self.is_ambient |= body.is_ambient; let body = FnBody::Block(self.stmts(body.stmts.slice(), false)); + self.is_ambient = was_ambient; self.b.file.fns[func.idx()].body = body; } PendingPart::PatternKey(property, key) => { @@ -207,12 +218,18 @@ impl<'p, 'a> Lower<'p, 'a> { let mut expression = self.expr(&written); // `parseExpressionWithTypeArguments`: type arguments that the expression // consumed belong to the element. + let mut consumed = None; if self.last_cast(&written) == Some(Mark::Instantiation) - && let ExprKind::Instantiation { expr, .. } = self.b.file[expression].kind + && let ExprKind::Instantiation { expr, type_args } = + self.b.file[expression].kind { expression = expr; + consumed = Some(type_args); + } + if let TypeNodeKind::Heritage { expr, args } = &mut self.b.file[node].kind { + *expr = expression; + *args = consumed.unwrap_or(*args); } - self.b.file[node].kind = TypeNodeKind::Heritage(expression); } } } @@ -398,21 +415,50 @@ impl<'p, 'a> Lower<'p, 'a> { } } if decorators { - self.check_js_decorator_syntax(list); + self.check_js_decorator_syntax(list, false); } } - /// `checkJSDecoratorSyntax`: the first decorator in `list`, the modifiers of a node for which - /// `CanHaveIllegalDecorators` is true. - fn check_js_decorator_syntax(&mut self, list: Span) { - let mut modifiers = self.b.file.modifier_list(list).iter(); - let first = modifiers.find_map(|modifier| match modifier.kind { - ModifierKind::Decorator(e) => Some((modifier.pos, e)), - ModifierKind::Keyword(_) => None, - }); - if let Some((pos, e)) = first { - let end = hir::end_of_expr(&self.b.file, e); - self.b.js_error_at_range((pos, end), 1206, b""); + /// `checkJSDecoratorSyntax` for a node whose modifiers are `list`: a class declaration + /// (`is_class_declaration`), or a node for which `CanHaveIllegalDecorators` is true. + fn check_js_decorator_syntax(&mut self, list: Span, is_class_declaration: bool) { + let file = &self.b.file; + let modifiers = file.modifier_list(list); + // Each with its index and its range. + let decorators = || { + let modifiers = modifiers.iter().enumerate(); + modifiers.filter_map(move |(index, modifier)| match modifier.kind { + ModifierKind::Decorator(e) => { + Some((index, (modifier.pos, hir::end_of_expr(file, e)))) + } + ModifierKind::Keyword(_) => None, + }) + }; + let index_of = |keyword: Flags| { + let mut modifiers = modifiers.iter(); + modifiers.position(|modifier| modifier.kind == ModifierKind::Keyword(keyword)) + }; + let Some((decorator_index, first)) = decorators().next() else { + return; + }; + if !is_class_declaration { + self.b.js_error_at_range(first, 1206, b""); + return; + } + let Some(export_index) = index_of(Flags::EXPORT) else { + return; + }; + let default_index = index_of(Flags::DEFAULT); + let trailing = decorators().find(|&(index, _)| index > export_index); + if decorator_index > export_index { + if default_index.is_some_and(|default_index| decorator_index < default_index) { + self.b.js_error_at_range(first, 1206, b""); + } + } else if let Some((_, trailing)) = trailing { + let mut diagnostic = Diagnostic::new(DiagnosticKind::Js, trailing, 8038, &[]); + let related = Diagnostic::new(DiagnosticKind::Js, first, 1486, &[]); + diagnostic.related.push(related); + self.b.file.diagnostics.push(diagnostic); } } @@ -420,20 +466,37 @@ impl<'p, 'a> Lower<'p, 'a> { /// nothing from its comments yet. fn check_js_syntax(&mut self, id: StmtId) { let stmt = self.b.file[id]; + match stmt.kind { + // `parseAmbientExternalModuleDeclaration` does not perform this check. + StmtKind::Module(m) if !matches!(self.b.file[m].name, ModuleName::Ident(_)) => return, + StmtKind::Class(_) => self.check_js_decorator_syntax(stmt.modifiers, true), + StmtKind::Var(_) + | StmtKind::Fn(_) + | StmtKind::Interface(_) + | StmtKind::TypeAlias(_) + | StmtKind::Enum(_) + | StmtKind::Module(_) + | StmtKind::ImportEquals(_) + | StmtKind::Import(_) + | StmtKind::ExportNamed(_) + | StmtKind::ExportStar { .. } + | StmtKind::ExportDefault(_) + | StmtKind::ExportAssign(_) => self.check_js_decorator_syntax(stmt.modifiers, false), + // Nor does `parseNamespaceExportDeclaration`. + _ => return, + } if let StmtKind::Fn(_) | StmtKind::Var(_) | StmtKind::Class(_) = stmt.kind { self.check_js_modifiers(stmt.modifiers, false); } let (file, whole) = (&self.b.file, (stmt.start, stmt.loc.end)); let (at, code, what): (_, _, &[u8]) = match stmt.kind { - StmtKind::Fn(f) if matches!(file[f].body, FnBody::None) => (whole, 8017, b""), + StmtKind::Fn(f) if !hir::has_body_node(&file[f]) => (whole, 8017, b""), StmtKind::Import(i) if file[i].type_only => (whole, 8006, b"import type"), StmtKind::ExportNamed(e) if file[e].type_only => (whole, 8006, b"export type"), StmtKind::ExportStar { type_only, .. } if type_only => (whole, 8006, b"export type"), StmtKind::ImportEquals(_) => (whole, 8002, b""), StmtKind::ExportAssign(_) => (whole, 8003, b""), StmtKind::Interface(i) => ((file[i].name_pos, 0), 8006, b"interface"), - // `parseAmbientExternalModuleDeclaration` does not perform this check. - StmtKind::Module(m) if !matches!(file[m].name, ModuleName::Ident(_)) => return, StmtKind::Module(m) if file[m].specifies_module => { ((file[m].name_pos, 0), 8006, b"module") } @@ -472,6 +535,7 @@ impl<'p, 'a> Lower<'p, 'a> { // parsed from. let was_module = self.b.file.has_module_syntax; let outer_reparsed = std::mem::take(&mut self.reparsed); + let outer_context = std::mem::replace(&mut self.is_in_appropriate_context, is_top_level); for stmt in stmts { if is_top_level && matches!( @@ -499,6 +563,7 @@ impl<'p, 'a> Lower<'p, 'a> { self.list_reparsed(); } self.reparsed = outer_reparsed; + self.is_in_appropriate_context = outer_context; if !is_top_level { self.b.file.has_module_syntax = was_module; } @@ -547,10 +612,12 @@ impl<'p, 'a> Lower<'p, 'a> { self.b.file.list(&out) } + /// `isAnExternalModuleIndicatorNode` fn is_exported(&self, id: StmtId) -> bool { let f = &self.b.file; let flags = match f[id].kind { - StmtKind::Var(decls) => decls.iter().next().map_or(Flags::empty(), |d| f[d].flags), + // Its declarations have its flags, and there may be none. + StmtKind::Var(_) => f.modifiers_to_flags(f[id].modifiers), StmtKind::Fn(x) => f[x].flags, StmtKind::Class(x) => f[x].flags, StmtKind::Interface(x) => f[x].flags, @@ -694,19 +761,23 @@ impl<'p, 'a> Lower<'p, 'a> { } fn stmt(&mut self, stmt: &Stmt) -> Option { - // `declare` makes the whole statement ambient. + // `parseDeclaration`: `declare` makes the statement ambient. let was_ambient = self.is_ambient; self.is_ambient |= self.modifier_flags_at(stmt.loc).contains(Flags::AMBIENT); - let id = self.stmt_in_context(stmt); + let id = self.stmt_in_context(stmt, was_ambient); self.is_ambient = was_ambient; id } - fn stmt_in_context(&mut self, stmt: &Stmt) -> Option { - let id = self.stmt_without_jsdoc(stmt); + /// `was_ambient`: `NodeFlagsAmbient` where the modifiers of `stmt` were parsed, its decorators + /// among them, which is before the parser knows of a `declare`. + fn stmt_in_context(&mut self, stmt: &Stmt, was_ambient: bool) -> Option { + let id = self.stmt_without_jsdoc(stmt, was_ambient); if let Some(id) = id { self.finish_stmt(id, stmt.loc); + let is_ambient = std::mem::replace(&mut self.is_ambient, was_ambient); self.statement_modifiers(stmt.loc, id); + self.is_ambient = is_ambient; if self.b.is_js { self.check_js_syntax(id); } @@ -780,7 +851,7 @@ impl<'p, 'a> Lower<'p, 'a> { } /// `withJSDoc` for the node `host` whose first token is at `token`, if the parser recorded its - /// full start. + /// full start. For an expression it does so in JavaScript only (`P::pos_for_jsdoc`). fn with_noted_jsdoc( &mut self, full_start: Option, @@ -788,9 +859,14 @@ impl<'p, 'a> Lower<'p, 'a> { with_trailing: bool, host: &mut Host, ) { - if !self.jsdoc.list.is_empty() - && let Some(full_start) = full_start - { + if self.jsdoc.list.is_empty() { + return; + } + let full_start = match full_start { + None if !self.b.is_js => self.first_comment_before(token), + _ => full_start, + }; + if let Some(full_start) = full_start { self.with_jsdoc(token, full_start, with_trailing, host); } } @@ -811,14 +887,14 @@ impl<'p, 'a> Lower<'p, 'a> { /// The initializer of a `for` statement, which is not a statement: a comment before it is /// attached to no node. fn for_initializer(&mut self, stmt: &Stmt) -> StmtId { - let id = match self.stmt_without_jsdoc(stmt) { + let id = match self.stmt_without_jsdoc(stmt, self.is_ambient) { Some(id) => id, None => self.b.file.stmt(StmtKind::Empty, self.pos_of(stmt.loc)), }; self.finish_stmt(id, stmt.loc) } - fn stmt_without_jsdoc(&mut self, stmt: &Stmt) -> Option { + fn stmt_without_jsdoc(&mut self, stmt: &Stmt, was_ambient: bool) -> Option { if !self.stack_check.is_safe_to_recurse() { self.b.file.syntax_errors += 1; self.b.file.ran_out_of_stack = true; @@ -998,7 +1074,7 @@ impl<'p, 'a> Lower<'p, 'a> { if s.is_export { flags |= Flags::EXPORT; } - StmtKind::Class(self.class(&s.class, flags, pos, start)) + StmtKind::Class(self.class(&s.class, flags, pos, start, was_ambient)) } StmtData::SExportDefault(s) => match &s.value { StmtOrExpr::Expr(e) => StmtKind::ExportDefault(self.expr(e)), @@ -1018,6 +1094,7 @@ impl<'p, 'a> Lower<'p, 'a> { | self.modifier_flags_at(stmt.loc) & Flags::ABSTRACT, pos, start, + was_ambient, )), _ => return self.stmt(inner), }, @@ -1272,9 +1349,20 @@ impl<'p, 'a> Lower<'p, 'a> { let expr = self.expr(key); self.b.computed_key(expr) } - // Only for a binding pattern, where a bigint is not an index type (2538). The source - // spelling is used, so `0n` does not match `0`. - Data::EBigInt(n) => PropKey::Name(self.b.atom(&[n.value.slice(), &b"n"[..]].concat())), + // Only for a binding pattern, where a bigint is not an index type (2538). `name.Text()` + // ends with the `n`, so `0n` does not match `0`. + Data::EBigInt(_) => { + let source = self.p.source.contents(); + let written = source + .get(self.pos_of(key.loc) as usize..) + .unwrap_or_default(); + let token = match bun_core::strings::index_of_char_usize(written, b'n') { + Some(at) => &written[..=at], + None => written, + }; + let text = bun_sema::json::bigint_token_value(token); + PropKey::Name(self.b.atom(&text)) + } _ => PropKey::None, } } @@ -1429,26 +1517,23 @@ impl<'p, 'a> Lower<'p, 'a> { Some(at) => self.type_at(at), None => TypeNodeId::NONE, }; + // `parseBlock` without its `{`: a missing block, which is not the same as no body. + if self.note(open, Mark::MissingBody).is_some() { + flags |= Flags::MISSING_BODY; + } // `parseFunctionBlockOrSemicolon`: no body at all after a semicolon. - let body = if func + let is_present = !func .flags - .contains(ast::flags::Function::IsForwardDeclaration) - { - FnBody::None - } else { + .contains(ast::flags::Function::IsForwardDeclaration); + // `checkJSSyntax`: unless `node.Body() == nil`, which is 8017. + if is_present || flags.contains(Flags::MISSING_BODY) { self.js_error_at_types(ret, ret, 8010); - // `checkGrammarStatementInAmbientContext`, `checkGrammarAccessor`: for anything that - // has a body in an ambient context. - if self.is_ambient || flags.contains(Flags::AMBIENT) { - let body = self.pos_of(func.body.loc); - self.b.file.error(DiagnosticKind::Grammar, body, 0, 1183); - } + } + let body = if is_present { FnBody::Block(self.stmts(func.body.stmts.slice(), false)) + } else { + FnBody::None }; - // `parseBlock` without its `{`: a missing block, which is not the same as no body. - if self.note(open, Mark::MissingBody).is_some() { - flags |= Flags::MISSING_BODY; - } // `createMissingList`: without a `(` the parameter list is at the end of the previous // token. The anchor is one before that position. let anchor = match self.note(open, Mark::MissingParameters) { @@ -1503,13 +1588,7 @@ impl<'p, 'a> Lower<'p, 'a> { ] if arrow.prefer_expr && ret.value.is_some() => { FnBody::Expr(self.expr(ret.value.as_ref().unwrap())) } - _ => { - if self.is_ambient { - let body = self.pos_of(arrow.body.loc); - self.b.file.error(DiagnosticKind::Grammar, body, 0, 1183); - } - FnBody::Block(self.stmts(stmts, false)) - } + _ => FnBody::Block(self.stmts(stmts, false)), }; let anchor = arrow_token.unwrap_or(pos); let created = self.b.file.add_fn(Func { @@ -1536,7 +1615,15 @@ impl<'p, 'a> Lower<'p, 'a> { created } - fn class(&mut self, class: &G::Class, flags: Flags, pos: u32, start: u32) -> ClassId { + /// `was_ambient`: `NodeFlagsAmbient` where its decorators were parsed (`stmt_in_context`). + fn class( + &mut self, + class: &G::Class, + flags: Flags, + pos: u32, + start: u32, + was_ambient: bool, + ) -> ClassId { let keyword = class.class_keyword.loc; // `GetContainingClass`: its decorators and heritage clauses are inside it too. self.b.classes_around += 1; @@ -1581,11 +1668,13 @@ impl<'p, 'a> Lower<'p, 'a> { .collect(); self.b.file.list(&elements) }); + let is_ambient = std::mem::replace(&mut self.is_ambient, was_ambient); let of_class: Vec<(ExprId, u32)> = class .ts_decorators .iter() .map(|d| (self.expr(d), self.at_sign(d))) .collect(); + self.is_ambient = is_ambient; let mut members = Vec::with_capacity(class.properties.slice().len()); // Keyed by the position of the member. They are sorted further down. let mut of_members: Vec<(u32, ExprId)> = Vec::new(); @@ -1648,7 +1737,12 @@ impl<'p, 'a> Lower<'p, 'a> { self.b.file.decorators.push((DecoratorOwner::Member(m), e)); } } - let modifiers = self.b.modifiers_with_decorators(Span::EMPTY, &of_class); + // `parseDecoratedExpression`: the keywords among the modifiers of a class expression. + let keywords = self.modifiers_at(keyword); + let keywords = self.b.add_modifier_list(&keywords); + self.check_js_modifiers(keywords, false); + let modifiers = self.b.modifiers_with_decorators(keywords, &of_class); + let flags = flags | self.modifier_flags_at(keyword) & Flags::ABSTRACT; let id = self.b.file.add_class(Class { name: class .class_name @@ -1685,17 +1779,25 @@ impl<'p, 'a> Lower<'p, 'a> { { self.b.js_error_at_range((question, 0), 8009, b"?"); } - if member.func.is_some() && matches!(self.b.file[member.func].body, FnBody::None) { + if member.func.is_some() && !hir::has_body_node(&self.b.file[member.func]) { self.b .js_error_at_range((member.start, member.loc.end), 8017, b""); } match member.kind { - MemberKind::IndexSignature => self.check_js_decorator_syntax(member.modifiers), + MemberKind::IndexSignature => self.check_js_decorator_syntax(member.modifiers, false), kind => self.check_js_modifiers(member.modifiers, kind == MemberKind::Constructor), } } fn class_member(&mut self, property: &G::Property) -> Member { + let was_ambient = self.is_ambient; + let member = self.class_member_in_context(property); + self.is_ambient = was_ambient; + member + } + + /// Leaves `is_ambient` as it is at the end of the member. + fn class_member_in_context(&mut self, property: &G::Property) -> Member { let mut member = Member { kind: MemberKind::Property, key: PropKey::None, @@ -1739,6 +1841,12 @@ impl<'p, 'a> Lower<'p, 'a> { member.name_pos = self.pos_of(key.loc); member.start = member.name_pos; let is_computed = property.flags.contains(ast::flags::Property::IsComputed); + let modifiers = self.modifiers_at(key.loc); + // `parseClassElement`: its own `declare` makes a property or a method ambient, from its + // name on. + let is_parent_ambient = self.is_ambient; + let is_accessor = matches!(property.kind, G::PropertyKind::Get | G::PropertyKind::Set); + self.is_ambient |= !is_accessor && modifiers.iter().any(|it| it.0 == Flags::AMBIENT); member.key = self.key(key, is_computed); // `getDeclarationName`: a bigint name declares nothing. let is_named_by_bigint = !is_computed && matches!(key.data, Data::EBigInt(_)); @@ -1748,13 +1856,14 @@ impl<'p, 'a> Lower<'p, 'a> { if let Some(start) = self.note(key.loc, Mark::MemberStart) { member.start = start; } - let modifiers = self.modifiers_at(key.loc); member.modifiers = self.b.add_modifier_list(&modifiers); - // Its own `declare` makes a property or a method ambient. - let is_parent_ambient = self.is_ambient; member.flags = modifiers .iter() .fold(self.ambient(), |flags, modifier| flags | modifier.0); + // `declareSymbolEx`: `isDefaultExport && parent != nil` + if member.flags.contains(Flags::DEFAULT) && matches!(member.key, PropKey::Name(_)) { + member.key = PropKey::Name(bun_sema::atom::known::default); + } if self.note(key.loc, Mark::Optional).is_some() { member.flags |= Flags::OPTIONAL; } else if self.note(key.loc, Mark::Definite).is_some() { @@ -1785,8 +1894,7 @@ impl<'p, 'a> Lower<'p, 'a> { data: Data::EFunction(f), loc, }) = &property.value - && (property.flags.contains(ast::flags::Property::IsMethod) - || matches!(property.kind, G::PropertyKind::Get | G::PropertyKind::Set)) + && (property.flags.contains(ast::flags::Property::IsMethod) || is_accessor) { // `tryParseConstructorDeclaration`: the keyword, or a string literal with the same text // directly before the `(`. Never `[..]`. @@ -1805,8 +1913,9 @@ impl<'p, 'a> Lower<'p, 'a> { member.kind = member_kind; member.ty = TypeNodeId::NONE; // `parseClassElement`: but not an accessor or a constructor. - if !is_parent_ambient && !matches!(member_kind, MemberKind::Method) { - member.flags.remove(Flags::AMBIENT); + if !matches!(member_kind, MemberKind::Method) { + self.is_ambient = is_parent_ambient; + member.flags.set(Flags::AMBIENT, is_parent_ambient); } // On a member these are only reported as errors. member @@ -1835,12 +1944,6 @@ impl<'p, 'a> Lower<'p, 'a> { member .flags .remove(Flags::CONST | Flags::EXPORT | Flags::DEFAULT); - // `checkVariableLikeDeclaration` - if is_named_by_bigint { - self.b - .file - .error(DiagnosticKind::Checker, member.name_pos, 0, 1539); - } member.init = self.optional_expr(property.initializer.as_ref().or(property.value.as_ref())); member } @@ -2005,6 +2108,17 @@ impl<'p, 'a> Lower<'p, 'a> { && self.b.file[name.at(0)].text == bun_sema::atom::known::r#const => { + // `checkAssertion` returns before it checks the type node, which + // is more than the word if it is `const<>`. + let TypeNode { + pos: from, end: to, .. + } = self.b.file[ty]; + if to.saturating_sub(from) > b"const".len() as u32 { + self.b.file.diagnostics.retain(|d| { + d.kind != DiagnosticKind::Grammar + || !(from..to).contains(&d.start) + }); + } ExprKind::AsConst(id) } _ => ExprKind::As { expr: id, ty }, @@ -2242,9 +2356,16 @@ impl<'p, 'a> Lower<'p, 'a> { ExprKind::Fn(func) } Data::EClass(e) => { - let class = self.class(e, Flags::empty(), pos, self.declaration_start(expr.loc)); - let full_start = self.full_start_of(expr.loc); - self.with_noted_jsdoc(full_start, pos, false, &mut Host::Class(class)); + let start = self.declaration_start(expr.loc); + let class = self.class(e, Flags::empty(), pos, start, self.is_ambient); + // `parseDecoratedExpression`: its comments are those before the decorators. The + // parser records the full start of `class`. + let full_start = if start == pos { + self.full_start_of(expr.loc) + } else { + self.first_comment_before(start) + }; + self.with_noted_jsdoc(full_start, start, false, &mut Host::Class(class)); ExprKind::Class(class) } Data::EDot(e) => { @@ -2594,11 +2715,20 @@ impl<'p, 'a> Lower<'p, 'a> { .note(key_in_source.loc, Mark::PostfixToken) .unwrap_or(0), }; + // `checkJSSyntax` if kind == PropKind::Method && let Some(question) = self.note(key_in_source.loc, Mark::Optional) { self.b.js_error_at_range((question, 0), 8009, b"?"); } + // Only a method or an accessor can be without a body. + if self.b.is_js + && value.is_some() + && let ExprKind::Fn(func) = self.b.file[value].kind + && !hir::has_body_node(&self.b.file[func]) + { + self.b.js_error_at_range((start, prop.end), 8017, b""); + } let written = self.modifiers_at(key_in_source.loc); if !written.is_empty() { let list = self.b.add_modifier_list(&written); diff --git a/src/js_parser/sema/lower_modules.rs b/src/js_parser/sema/lower_modules.rs index 4f91e63789a5..22cbefdd2826 100644 --- a/src/js_parser/sema/lower_modules.rs +++ b/src/js_parser/sema/lower_modules.rs @@ -133,6 +133,7 @@ impl Lower<'_, '_> { clause_end: pos(import.clause_end), namespace_start, named, + has_named_imports: import.specifiers.is_some(), type_only: import.is_type_only, is_deferred: import.is_deferred, mode, diff --git a/src/js_parser/sema/mod.rs b/src/js_parser/sema/mod.rs index c367fdf04b67..d590465a4f64 100644 --- a/src/js_parser/sema/mod.rs +++ b/src/js_parser/sema/mod.rs @@ -230,19 +230,11 @@ pub(crate) fn early_error(msg: &bun_ast::Msg) -> Option<(u32, i32)> { early_error_in_place(text).map(|code| (code, 0)) } -/// Converts a logged error and its notes to the diagnostic TypeScript reports. `Some(None)`: no diagnostic, because the checker -/// detects the error itself. `None`: an unrecognized error, so the AST is unreliable. `has_jsx`: `LanguageVariantJSX`. -pub(crate) fn diagnostic( - msg: &bun_ast::Msg, - source: &[u8], - has_jsx: bool, -) -> Option> { - let location = msg.data.location.as_ref()?; - let (text, mut len) = (&msg.data.text[..], location.length); - let at = source.get(location.offset..).unwrap_or_default(); - let (code, delta) = early_error(msg)?; - let kind = match msg.metadata { - _ if code == 0 => return Some(None), +/// The component of TypeScript that reports the logged error `msg`, which has `code`. `None`: the +/// checker detects the error itself. +fn reporter_of(msg: &bun_ast::Msg, code: u32) -> Option { + Some(match msg.metadata { + _ if code == 0 => return None, Metadata::TypeScript { kind, .. } => match kind { TypeScriptKind::Parse => DiagnosticKind::Parse, TypeScriptKind::Grammar => DiagnosticKind::Grammar, @@ -251,20 +243,38 @@ pub(crate) fn diagnostic( // `Lexer::expected` and `Lexer::unexpected` _ if matches!(code, 1003 | 1005 | 1109) => DiagnosticKind::Parse, // `createIdentifierWithDiagnostic`, at a reserved word. - _ if code == 1359 && text.starts_with(b"Expected identifier ") => DiagnosticKind::Parse, + _ if code == 1359 && msg.data.text.starts_with(b"Expected identifier ") => { + DiagnosticKind::Parse + } _ => DiagnosticKind::Grammar, + }) +} + +/// Whether the logged message `msg` is one of `Parser.diagnostics`: an error of TypeScript's parser +/// or scanner, not of its checker. +pub(crate) fn is_parse_error(msg: &bun_ast::Msg) -> bool { + msg.kind == bun_ast::Kind::Err + && early_error(msg) + .is_none_or(|(code, _)| reporter_of(msg, code) == Some(DiagnosticKind::Parse)) +} + +/// Converts a logged error and its notes to the diagnostic TypeScript reports. `Some(None)`: no diagnostic, because the checker +/// detects the error itself. `None`: an unrecognized error, so the AST is unreliable. +pub(crate) fn diagnostic(msg: &bun_ast::Msg, source: &[u8]) -> Option> { + let location = msg.data.location.as_ref()?; + let mut len = location.length; + let at = source.get(location.offset..).unwrap_or_default(); + let (code, delta) = early_error(msg)?; + let Some(kind) = reporter_of(msg, code) else { + return Some(None); }; - match at { - // `Scan` produces one token for ` len = 2, - // `Scan` always produces a single `>`. `reScanGreaterThanToken` only runs after an operand, where 1005 is reported. - [b'>', b'>' | b'=', ..] if !matches!(code, 1005 | 1185) => len = len.min(1), - _ => {} + // `Scan` always produces a single `>`. `reScanGreaterThanToken` only runs after an operand, where 1005 is reported. + if matches!(at, [b'>', b'>' | b'=', ..]) && !matches!(code, 1005 | 1185) { + len = len.min(1); } - // `Lexer::add_related_info`. TypeScript attaches one message to each of these errors. + // `Lexer::add_related_info`. TypeScript attaches one message to this error. let related_code = match code { 1005 => 1007, - 8038 => 1486, _ => 0, }; let mut related: Vec = (msg.notes.iter()) @@ -456,12 +466,13 @@ pub fn summarize<'s>( use bun_sema::resolve::ScriptKind; let by_name = script_kind.is_none(); let is_declaration_file = by_name && bun_sema::resolve::is_declaration_file_name(path); - let is_js = script_kind.map_or_else( - || bun_sema::resolve::is_javascript(path), - ScriptKind::is_javascript, - ); - let is_json = by_name && path.ends_with(b".json"); - let is_tsx = script_kind.map_or_else(|| path.ends_with(b".tsx"), |it| it == ScriptKind::Tsx); + // `GetScriptKindFromFileName`: whatever the case of the extension. + let script_kind = script_kind.or_else(|| ScriptKind::from_file_name(path)); + let is_js = script_kind.is_some_and(ScriptKind::is_javascript); + let is_json = by_name + && (path.len().checked_sub(b".json".len())) + .is_some_and(|dot| path[dot..].eq_ignore_ascii_case(b".json")); + let is_tsx = script_kind == Some(ScriptKind::Tsx); // `getLanguageVariant`: JSX is enabled in all JavaScript files, and in JSON. let loader = if is_js || is_tsx || is_json { bun_ast::Loader::Tsx @@ -470,52 +481,55 @@ pub fn summarize<'s>( }; // Parses the file once. Also returns whether it must be parsed again with `await` as an // identifier at the top level. - let parse = - |await_is_a_name: bool, arena: &bun_alloc::Arena| -> (bun_sema::hir::FileBuilder, bool) { - let mut ast_memory_allocator = bun_ast::ASTMemoryAllocator::borrowing(arena); - let _ast_scope = ast_memory_allocator.enter(); - let source = bun_ast::Source::init_path_string(path, text); - let mut options = crate::ParserOptions::init(Default::default(), loader); - options.features.no_macros = true; - options.features.top_level_await = true; - options.features.standard_decorators = !experimental_decorators; - options.suppress_warnings_about_weird_code = true; - options.tolerant = true; - // `initializeState` - options.is_javascript = is_js || is_json; - let define = crate::Define::default(); - let mut log = bun_ast::Log::init(); - let (file, awaited) = - match crate::Parser::init(options, &mut log, &source, &define, arena) { - Ok(parser) => parser.parse_for_sema( - atoms, - is_declaration_file, - is_json, - await_is_a_name, - &parsing, - ), - Err(_) => ( - bun_sema::hir::FileBuilder { - has_errors: true, - ..Default::default() - }, - false, - ), - }; - // `parseSourceFileWorker`: only a file with an `ExternalModuleIndicator` has an [Await] context at its top level. - let parse_again = awaited - && !await_is_a_name - && !every_file_is_a_module - && !file.has_module_syntax - && ![&b".mts"[..], b".cts", b".mjs", b".cjs"] - .iter() - .any(|e| path.ends_with(e)) - && !file - .exprs - .iter() - .any(|e| matches!(e.kind, bun_sema::hir::ExprKind::ImportMeta)); - (file, parse_again) + let parse = |await_is_a_name: bool, + statements: &mut Vec, + arena: &bun_alloc::Arena| + -> (bun_sema::hir::FileBuilder, bool) { + let mut ast_memory_allocator = bun_ast::ASTMemoryAllocator::borrowing(arena); + let _ast_scope = ast_memory_allocator.enter(); + let source = bun_ast::Source::init_path_string(path, text); + let mut options = crate::ParserOptions::init(Default::default(), loader); + options.features.no_macros = true; + options.features.top_level_await = true; + options.features.standard_decorators = !experimental_decorators; + options.suppress_warnings_about_weird_code = true; + options.tolerant = true; + // `initializeState` + options.is_javascript = is_js || is_json; + let define = crate::Define::default(); + let mut log = bun_ast::Log::init(); + let (file, awaited) = match crate::Parser::init(options, &mut log, &source, &define, arena) + { + Ok(parser) => parser.parse_for_sema( + atoms, + is_declaration_file, + is_json, + await_is_a_name, + statements, + &parsing, + ), + Err(_) => ( + bun_sema::hir::FileBuilder { + has_errors: true, + ..Default::default() + }, + false, + ), }; + // `parseSourceFileWorker`: only a file with an `ExternalModuleIndicator` has an [Await] context at its top level. + let parse_again = awaited + && !await_is_a_name + && !every_file_is_a_module + && !file.has_module_syntax + && ![&b".mts"[..], b".cts", b".mjs", b".cjs"] + .iter() + .any(|e| path.ends_with(e)) + && !file + .exprs + .iter() + .any(|e| matches!(e.kind, bun_sema::hir::ExprKind::ImportMeta)); + (file, parse_again) + }; // What a file leaves in the arena is garbage. The arena is reset after this much source, not // after every file. const SOURCE_AT_MOST: usize = 256 << 10; @@ -526,9 +540,11 @@ pub fn summarize<'s>( *parsed = 0; } *parsed += text.len(); - let (file, parse_again) = parse(false, arena); + let mut statements = Vec::new(); + let (file, parse_again) = parse(false, &mut statements, arena); match parse_again { - true => parse(true, arena).0, + true => parse(true, &mut Vec::new(), arena).0, + false if !statements.is_empty() => parse(false, &mut statements, arena).0, false => file, } }); @@ -570,8 +586,11 @@ pub(crate) struct TypeSyntax<'a> { pub(crate) b: builder::Builder<'a>, /// `CommentTypes::created`, while the comments are parsed. pub(crate) comment_rows: Vec<(notes::Rows, notes::Rows)>, - /// The most recently parsed type. `NONE` if there is no usable type. + /// The most recently parsed type. `NONE` if there is no usable type. Written by `set_last_type`. pub(crate) last_type: ts::TypeId, + /// The most recently parsed type is a function type, in parentheses or not, whose parameter list is missing, or the return type + /// of one that has a list is (`typeHasArrowFunctionBlockingParseError`). An unusable type has no node to say so. + pub(crate) last_type_lacks_parameters: bool, /// Position of the first token of the type `parse_and_keep_type` parsed last. pub(crate) last_type_start: i32, /// Shared stack for the members of unions, intersections and type argument lists that are still being parsed. @@ -609,6 +628,8 @@ pub(crate) struct TypeSyntax<'a> { pub(crate) statement_modifiers_base: usize, /// The statements being parsed that start with `import` or `export`, the innermost last. pub(crate) module_syntax: Vec, + /// `P::note_function_context` + pub(crate) function_contexts: Vec, } impl<'a> TypeSyntax<'a> { @@ -624,6 +645,7 @@ impl<'a> TypeSyntax<'a> { b, comment_rows: Vec::new(), last_type: ts::TypeId::NONE, + last_type_lacks_parameters: false, last_type_start: 0, type_stack: Vec::new(), name_stack: Vec::new(), @@ -642,6 +664,7 @@ impl<'a> TypeSyntax<'a> { statement_modifiers: Vec::new(), statement_modifiers_base: 0, module_syntax: Vec::new(), + function_contexts: Vec::new(), } } } diff --git a/src/js_parser/sema/notes.rs b/src/js_parser/sema/notes.rs index 0db3d935da4b..5fd24c077bf2 100644 --- a/src/js_parser/sema/notes.rs +++ b/src/js_parser/sema/notes.rs @@ -18,7 +18,7 @@ use super::{Mark, TypeSyntax}; use crate::p::P; -use crate::parser::{SkipTypeParameterResult, TypeParameterFlag}; +use crate::parser::{AwaitOrYield, SkipTypeParameterResult, TypeParameterFlag}; use crate::sema::ts_syntax as ts; use bun_ast::{Expr, Loc}; @@ -59,12 +59,22 @@ pub(crate) struct Checkpoint { unclosed_literals: u32, type_stack: u32, name_stack: u32, + function_contexts: u32, rows: Rows, /// Index in `TypeSyntax::saved_results`. Not the results themselves: an ordinary build makes /// and copies checkpoints too. results: u32, } +/// `P::note_function_context` +#[derive(Copy, Clone)] +pub(crate) struct FunctionContext { + pub(crate) start: Loc, + pub(crate) end: Loc, + pub(crate) allow_await: AwaitOrYield, + pub(crate) allow_yield: AwaitOrYield, +} + /// What `TypeSyntax` holds for the caller of the function that parsed it. A speculative parse /// overwrites it: in `A | ({ [P in B]: D })` the lookahead for a function type after the `|` /// parses ``, while `A` is the type parsed last. @@ -72,6 +82,7 @@ pub(crate) struct Checkpoint { pub(crate) struct Results { pending_type_arguments: Option<(u32, Loc)>, last_type: ts::TypeId, + last_type_lacks_parameters: bool, last_type_start: i32, last_type_args: Option, last_binding: ts::PatternId, @@ -799,6 +810,40 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> self.note_token_full_start(named_at, Mark::MemberEnd); } + /// `setContextFlags`: from `start` (the `(` of a function, the `=>` of an arrow function, the + /// `{` of a static block) to the end of the previous token, `allow_await` and `allow_yield` + /// were in effect. Those around it are in effect again. For the comments of a JavaScript file, + /// which are parsed after the file (`withJSDoc` parses them in the contexts of their place). + /// Nothing is recorded where neither context is on inside or around. + #[inline] + pub(crate) fn note_function_context( + &mut self, + start: Loc, + allow_await: AwaitOrYield, + allow_yield: AwaitOrYield, + ) { + if !SEMA { + return; + } + let end = self.lexer.full_start(); + let (around, off) = (&self.fn_or_arrow_data_parse, AwaitOrYield::AllowIdent); + let is_on = allow_await != off + || allow_yield != off + || around.allow_yield != off + || (around.allow_await != off && !around.is_top_level); + if is_on + && let Some(syntax) = &mut self.type_syntax + && syntax.has_jsdoc + { + syntax.function_contexts.push(FunctionContext { + start, + end, + allow_await, + allow_yield, + }); + } + } + /// `mark`: pass the result to `rewind_type_syntax` if the parse from this point on is /// abandoned, and to `release_type_syntax_checkpoint` if it succeeds. #[inline] @@ -813,6 +858,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool, const SEMA: bool> unclosed_literals: syntax.unclosed_literals.len() as u32, type_stack: syntax.type_stack.len() as u32, name_stack: syntax.name_stack.len() as u32, + function_contexts: syntax.function_contexts.len() as u32, rows: syntax.rows(), results: syntax.save_results(), }, @@ -844,6 +890,7 @@ impl TypeSyntax<'_> { self.saved_results.push(Results { pending_type_arguments: self.pending_type_arguments, last_type: self.last_type, + last_type_lacks_parameters: self.last_type_lacks_parameters, last_type_start: self.last_type_start, last_type_args: self.last_type_args, last_binding: self.last_binding, @@ -886,11 +933,14 @@ impl TypeSyntax<'_> { .truncate(snapshot.unclosed_literals as usize); self.type_stack.truncate(snapshot.type_stack as usize); self.name_stack.truncate(snapshot.name_stack as usize); + self.function_contexts + .truncate(snapshot.function_contexts as usize); self.rewind_rows(snapshot.rows); let results = self.saved_results[snapshot.results as usize]; self.saved_results.truncate(snapshot.results as usize); self.pending_type_arguments = results.pending_type_arguments; self.last_type = results.last_type; + self.last_type_lacks_parameters = results.last_type_lacks_parameters; self.last_type_start = results.last_type_start; self.last_type_args = results.last_type_args; self.last_binding = results.last_binding; diff --git a/src/js_parser/sema/reparse.rs b/src/js_parser/sema/reparse.rs index 4ab40197aa17..8e2525cc342e 100644 --- a/src/js_parser/sema/reparse.rs +++ b/src/js_parser/sema/reparse.rs @@ -8,6 +8,7 @@ use std::rc::Rc; +use crate::lexer::{PragmaArg, end_of_run, is_white_space_single_line}; use crate::sema::ts_syntax as ts; use bun_sema::atom::{Atom, known}; use bun_sema::hir::*; @@ -50,6 +51,8 @@ struct Attached { /// From the start of the first of all the JSDoc comments to the end of the last. `None`: there /// is none. range: Option, + /// `jsdocScannerInfoHasSeeOrLink` + has_see_or_link: bool, } /// The modifier flags in `flags`, which an overload signature shares with the implementation. @@ -78,6 +81,7 @@ impl<'p, 'a> Lower<'p, 'a> { docs: SmallVec::new(), last_has_tags: false, range: None, + has_see_or_link: false, }; // `GetLeadingCommentRanges`: the comments after the first line break, or after the start of // the file. @@ -87,6 +91,7 @@ impl<'p, 'a> Lower<'p, 'a> { .zip(&lexer.comment_flags[first..]) .take_while(|(comment, _)| (comment.loc.start as u32) < token); for (comment, &reported) in comments { + attached.has_see_or_link |= reported & flags::SEE_OR_LINK != 0; is_collecting |= reported & flags::LINE_BREAK_BEFORE != 0; if !is_collecting || reported & flags::JSDOC_LIKE == 0 { // A line comment ends with its line. @@ -113,6 +118,24 @@ impl<'p, 'a> Lower<'p, 'a> { attached } + /// The start of the first comment in the trivia before the token at `token`. As a full start it + /// selects the same comments as `TokenFullStart`, unless that is the start of the file. + pub(super) fn first_comment_before(&self, token: u32) -> Option { + let lexer = &self.p.lexer; + let is_blank = |c| is_white_space_single_line(c) || PragmaArg::is_newline(c); + let before = lexer + .all_comments + .partition_point(|comment| (comment.loc.start as u32) < token); + let mut first = token as usize; + for comment in lexer.all_comments[..before].iter().rev() { + if end_of_run(lexer.contents, comment.end_i(), is_blank) < first { + break; + } + first = comment.loc.to_usize(); + } + (first < token as usize).then_some(first as u32) + } + /// `withJSDoc` for the node `host` whose first token is at `token`, with full start /// `full_start`. pub(super) fn with_jsdoc( @@ -126,7 +149,9 @@ impl<'p, 'a> Lower<'p, 'a> { return; } let attached = self.jsdoc_before(token, full_start, with_trailing); - if let Some(comments) = attached.range { + if self.b.is_js + && let Some(comments) = attached.range + { let docs = attached.docs.iter(); let mut tags = docs.flat_map(|&doc| &self.jsdoc.list[doc as usize].tags); let first_satisfies_tag = tags.find(|tag| matches!(tag.kind, TagKind::Satisfies(_))); @@ -176,7 +201,12 @@ impl<'p, 'a> Lower<'p, 'a> { /// Called once everything is lowered: stores the information collected about the comments in /// the file. pub(super) fn finish_jsdoc(&mut self) { + // `parseJSDocComment`: "move jsdoc diagnostics to jsdocDiagnostics -- for JS files only" + if !self.b.is_js { + return; + } let file = &mut self.b.file; + file.jsdoc_asterisks.clone_from(&self.jsdoc.asterisks); for (doc, &is_attached) in self.jsdoc.list.iter().zip(&self.jsdoc_is_attached) { file.jsdoc_comments.push((doc.start, doc.end)); if is_attached { @@ -599,17 +629,23 @@ impl<'p, 'a> Lower<'p, 'a> { // ───────────────────────────── tags ───────────────────────────── - /// `reparseTags` + /// `reparseTags`, which `withJSDoc` calls in JavaScript only, and what the checker reads from + /// the tags of `host` in every file. fn reparse_tags(&mut self, host: &mut Host, attached: &Attached) { let comments = Rc::clone(&self.jsdoc); - if let Host::Class(class) = *host { + let is_js = self.b.is_js; + // `EagerJSDoc`: in TypeScript `withJSDoc` parses the comments only if one has a link. + if let Host::Class(class) = *host + && (is_js || attached.has_see_or_link) + { self.check_grammar_augments_tags(class, attached); } for (i, &index) in attached.docs.iter().enumerate() { self.jsdoc_is_attached[index as usize] = true; let doc = &comments.list[index as usize]; let is_last = attached.last_has_tags && i + 1 == attached.docs.len(); - for tag in &doc.tags { + let reparsed: &[Tag] = if is_js { &doc.tags } else { &[] }; + for tag in reparsed { self.reparse_unhosted(tag, host, doc); if is_last { self.reparse_hosted(tag, host, doc); @@ -706,7 +742,10 @@ impl<'p, 'a> Lower<'p, 'a> { if !import.has_clause { return; } - self.note_checker_errors(tag.pos, import.end); + // `checkImportDeclaration` returns after `checkGrammarModuleElementContext`. + if self.is_in_appropriate_context { + self.note_checker_errors(tag.pos, import.end); + } if let Some(module) = import.module { self.unchecked_parts_of_module_specifier(module); } @@ -757,6 +796,7 @@ impl<'p, 'a> Lower<'p, 'a> { clause_end: import.clause_end, namespace_start: import.namespace_start, named: self.b.file.add_import_specs(&named), + has_named_imports: import.has_named_imports, type_only: true, is_deferred: false, mode, @@ -1131,7 +1171,8 @@ impl<'p, 'a> Lower<'p, 'a> { /// `checkGrammarClassDeclarationHeritageClauses`: the last name of an `@augments` or `@extends` /// tag, in any comment of the class, is the last name of the `extends` clause. It returns at the - /// first error. + /// first error. The checker decides between this error and the other errors of that function + /// (`Checker::check_grammar_augments_tags`). fn check_grammar_augments_tags(&mut self, class: ClassId, attached: &Attached) { let extends = self.b.file[class].extends; if extends.is_none() || self.paren_of(extends).is_some() { @@ -1155,6 +1196,8 @@ impl<'p, 'a> Lower<'p, 'a> { let at = (source.start, source.end); let diagnostic = Diagnostic::new(DiagnosticKind::Grammar, at, 8023, &names); self.b.file.diagnostics.push(diagnostic); + let file = &mut self.b.file; + file.unmatched_augments_tags.push((class, source.start)); return; } } @@ -1464,6 +1507,10 @@ impl<'p, 'a> Lower<'p, 'a> { return; }; self.b.file.functions_with_param_tags.push(func); + // `isJs` + if !self.b.is_js { + return; + } let mut names = Vec::new(); let mut is_pattern = Vec::new(); for param in self.b.file[func].params.iter() { diff --git a/src/js_parser/sema/ts_syntax.rs b/src/js_parser/sema/ts_syntax.rs index 34b1318d972b..e5860abf835c 100644 --- a/src/js_parser/sema/ts_syntax.rs +++ b/src/js_parser/sema/ts_syntax.rs @@ -191,6 +191,8 @@ pub(crate) struct FunctionBody { /// `node.End()` pub(crate) end: Loc, pub(crate) stmts: StoreSlice, + /// `NodeFlagsAmbient`, by a `declare` around it. + pub(crate) is_ambient: bool, } /// `(this: A, b: B): R` diff --git a/src/js_parser/typescript.rs b/src/js_parser/typescript.rs index 665ac677275e..87dff3bd9fcf 100644 --- a/src/js_parser/typescript.rs +++ b/src/js_parser/typescript.rs @@ -51,10 +51,14 @@ impl<'a, const TS: bool, const SCAN: bool, const SEMA: bool> P<'a, TS, SCAN, SEM // Look ahead to see if this should be an arrow function instead let mut is_ts_arrow_fn = false; - if p.lexer.token == T::TConst { + let is_const = p.lexer.token == T::TConst; + if is_const { p.lexer.next()?; } - if p.lexer.token == T::TIdentifier { + if p.lexer.token == T::TIdentifier + // `nextIsParenthesizedArrowFunctionExpression`: `isIdentifier`, of the token after "<". + && (is_const || !p.is_tolerant() || p.is_identifier_in_context()) + { p.lexer.next()?; if p.lexer.token == T::TComma || p.lexer.token == T::TEquals { is_ts_arrow_fn = true; @@ -71,11 +75,23 @@ impl<'a, const TS: bool, const SCAN: bool, const SEMA: bool> P<'a, TS, SCAN, SEM Ok(is_ts_arrow_fn) } + /// `p.token`. For the checker a reserved word is that keyword also if it is written with an + /// escape, as for TypeScript's scanner. The transpiler rejects such a word wherever it is no + /// name. + #[inline(always)] + fn ts_token(&self) -> T { + if self.is_tolerant() { + self.token() + } else { + self.lexer.token + } + } + // This function is taken from the official TypeScript compiler source code: // https://github.com/microsoft/TypeScript/blob/master/src/compiler/parser.ts pub(crate) fn is_binary_operator(&self) -> bool { let p = self; - match p.lexer.token { + match p.ts_token() { T::TIn => p.allow_in, T::TQuestionQuestion @@ -113,7 +129,7 @@ impl<'a, const TS: bool, const SCAN: bool, const SEMA: bool> P<'a, TS, SCAN, SEM // https://github.com/microsoft/TypeScript/blob/master/src/compiler/parser.ts pub(crate) fn is_start_of_left_hand_side_expression(&mut self) -> bool { let p = self; - match p.lexer.token { + match p.ts_token() { T::TThis | T::TSuper | T::TNull @@ -187,7 +203,7 @@ impl<'a, const TS: bool, const SCAN: bool, const SEMA: bool> P<'a, TS, SCAN, SEM return true; } - match p.lexer.token { + match p.ts_token() { T::TPlus | T::TMinus | T::TTilde diff --git a/src/sema/Cargo.toml b/src/sema/Cargo.toml index cb0a4ba62813..c67fe3d6bd89 100644 --- a/src/sema/Cargo.toml +++ b/src/sema/Cargo.toml @@ -15,7 +15,6 @@ bun_alloc.workspace = true bun_collections.workspace = true bun_core.workspace = true bun_paths.workspace = true -bun_semver.workspace = true bun_threading.workspace = true bun_wyhash.workspace = true bstr.workspace = true diff --git a/src/sema/baselines/lib.rs b/src/sema/baselines/lib.rs index cebafb267828..cf91ebbd41f7 100644 --- a/src/sema/baselines/lib.rs +++ b/src/sema/baselines/lib.rs @@ -1538,7 +1538,7 @@ fn run_one( config_path.as_bytes(), &|_| Vec::new(), ); - named_by_config = Some(project.files); + named_by_config = project.ok().map(|project| project.files); config_unit = Some(units.remove(at)); } @@ -1622,19 +1622,16 @@ fn run_one( } // `compileFilesWithHost` creates two programs from it. let parsed_command_line = || -> Project { - let mut project: Project = match &config_unit { - Some(unit) => { - let mut over = reported.clone(); - defaults(&mut over); - let path = absolute(&unit.name, &cwd); - config::load_overriding(&host, &Session::new(), path.as_bytes(), &|_| over.clone()) - } - None => { - let mut compiler = reported.clone(); - defaults(&mut compiler); - config::without_config(&host, cwd.as_bytes(), Json::Object(compiler), files.clone()) - } - }; + let mut compiler = reported.clone(); + defaults(&mut compiler); + let from_config_file = config_unit.as_ref().and_then(|unit| { + let path = absolute(&unit.name, &cwd); + let over = |_: bool| compiler.clone(); + config::load_overriding(&host, &Session::new(), path.as_bytes(), &over).ok() + }); + let mut project: Project = from_config_file.unwrap_or_else(|| { + config::without_config(&host, cwd.as_bytes(), Json::Object(compiler), files.clone()) + }); // `compileDeclarationFiles` passes on `ConfigFile` and not `Errors`. if declaration_files.is_some() { project.errors.clear(); diff --git a/src/sema/bind/binder.rs b/src/sema/bind/binder.rs index 0b1fd797b28d..fe2ca7346b8a 100644 --- a/src/sema/bind/binder.rs +++ b/src/sema/bind/binder.rs @@ -89,6 +89,12 @@ pub(super) struct Binder<'f, 's> { cur_member: MemberId, /// `thisContainer`, if it is a member of a class. this_member: MemberId, + /// `thisContainer`, if it is a method or an accessor of an object literal. + this_property: PropId, + /// `GetContainingClass`, applied repeatedly to the node being bound. The innermost is the last. + containing_classes: Vec, + /// The node being bound is in a decorator of the last of `containing_classes` itself. + is_in_class_decorator: bool, returns: Vec, yields: Vec, /// `seenThisKeyword` @@ -112,6 +118,13 @@ pub(super) struct Binder<'f, 's> { stack_check: bun_core::StackCheck, } +/// See `Binder::assignment_target_in`. +#[derive(Copy, Clone)] +struct ReachedBy { + is_bound: bool, + is_checked: bool, +} + impl<'f, 's> Binder<'f, 's> { pub(super) fn run( f: &'f File<'s>, @@ -209,6 +222,9 @@ impl<'f, 's> Binder<'f, 's> { cur_fn: FnId::NONE, cur_member: MemberId::NONE, this_member: MemberId::NONE, + this_property: PropId::NONE, + containing_classes: Vec::new(), + is_in_class_decorator: false, returns: Vec::new(), yields: Vec::new(), seen_this: false, @@ -408,15 +424,10 @@ impl<'f, 's> Binder<'f, 's> { /// `GetContainingClass` for the declaration being bound. fn containing_class(&self) -> ClassId { - let mut scope = self.scope; - while scope.is_some() { - let s = &self.b.scopes[scope.idx()]; - if let ScopeKind::Class(class) = s.kind { - return class; - } - scope = s.parent; - } - ClassId::NONE + self.containing_classes + .last() + .copied() + .unwrap_or(ClassId::NONE) } /// Notes `decl`, which no class declares, if its name `key` is an `#x`. @@ -504,7 +515,7 @@ impl<'f, 's> Binder<'f, 's> { /// `HasDynamicName`). With `is_computed_name` the original has one `__computed` symbol in the /// table for all of them. Here each has its own, in no table: /// `Checker::declarations_of_property` identifies a late-bound symbol by the symbol of its first - /// declaration. + /// declaration. `Bound::computed_symbols` lists them by table. fn declare_symbol_ex( &mut self, table: TableId, @@ -571,6 +582,9 @@ impl<'f, 's> Binder<'f, 's> { } } }; + if is_computed_name == IsComputedName::Yes { + self.b.computed_symbols.push((table, symbol)); + } self.add_declaration_to_symbol(symbol, decl, includes); let there = &mut self.b.symbols[symbol.idx()]; // A symbol with any declaration other than `export { a as b }` is in scope. @@ -593,6 +607,7 @@ impl<'f, 's> Binder<'f, 's> { || match decl { Decl::ExportSpec(it) => f[it].exported == known::default, Decl::ExportExpr(it) => matches!(f[it].kind, StmtKind::ExportDefault(_)), + Decl::Member(it) => f.find_modifier(f[it].modifiers, Flags::DEFAULT).is_some(), _ => false, }; let code = if is_default_export { @@ -719,10 +734,9 @@ impl<'f, 's> Binder<'f, 's> { } } - /// The `module "m" { }` or `global { }` at the top level of a script whose body directly - /// contains the node being bound. - fn ambient_module_around(&self) -> Option { - let s = &self.b.scopes[self.scope.idx()]; + /// The `module "m" { }` or `global { }` at the top level of a script whose body `scope` is. + fn ambient_module_around(&self, scope: ScopeId) -> Option { + let s = &self.b.scopes[scope.idx()]; match s.kind { ScopeKind::Module(m) if !self.f.has_module_syntax @@ -742,7 +756,7 @@ impl<'f, 's> Binder<'f, 's> { if matches!(self.b.scopes[self.scope.idx()].kind, ScopeKind::File) { self.specifier(spec); } else if spec.is_some() - && let Some(m) = self.ambient_module_around() + && let Some(m) = self.ambient_module_around(self.scope) && (self.f[m].flags.contains(Flags::AMBIENT) || self.f.kind == FileKind::Declaration) { self.b.ambient_specifiers.push(spec); @@ -1053,43 +1067,90 @@ impl<'f, 's> Binder<'f, 's> { /// `bindAssignmentTargetFlow` fn assignment_target(&mut self, e: ExprId) { - self.assignment_target_in(e, true); + self.assignment_target_in( + e, + ReachedBy { + is_bound: true, + is_checked: true, + }, + ); } /// `is_bound`: `bindAssignmentTargetFlow` gets as far as `e`. It enters neither a /// parenthesized pattern, nor `x!`, nor an assignment. `GetAssignmentTarget` climbs out of all /// three, so for `markNodeAssignmentsWorker` the names in there are assigned as well. - fn assignment_target_in(&mut self, e: ExprId, is_bound: bool) { - let enters = is_bound && !is_parenthesized(self.f, e); + /// `is_checked`: so does `checkDestructuringAssignment`, see `unchecked_assignment_targets`. A + /// parenthesized pattern is an expression to it, which it checks whole. + fn assignment_target_in(&mut self, e: ExprId, reached_by: ReachedBy) { + let ReachedBy { + is_bound, + is_checked, + } = reached_by; + let is_expression = is_parenthesized(self.f, e); + let enters = is_bound && !is_expression; match self.f[e].kind { ExprKind::Array(items) => { - for item in self.f.ids(items) { - let target = match self.f[item].kind { - ExprKind::Spread(x) => x, - _ => self.destructuring_target(item), + for (i, item) in self.f.ids(items).enumerate() { + let (target, is_visited) = match self.f[item].kind { + ExprKind::Spread(x) => { + let is_last = i + 1 == items.len(); + (x, is_last && self.destructuring_target(x) == x) + } + _ => (self.destructuring_target(item), true), + }; + let is_checked = is_checked && (is_expression || is_visited); + let reached_by = ReachedBy { + is_bound: enters, + is_checked, }; - self.assignment_target_in(target, enters); + self.assignment_target_in(target, reached_by); } return; } ExprKind::Object(props) => { - for p in props.iter() { + for (i, p) in props.iter().enumerate() { let (kind, value) = (self.f[p].kind, self.f[p].value); if value.is_none() { continue; } - let target = match kind { - PropKind::Spread => value, - _ => self.destructuring_target(value), + let (target, is_visited) = match kind { + PropKind::Spread => (value, i + 1 == props.len()), + _ => (self.destructuring_target(value), true), + }; + let is_checked = is_checked && (is_expression || is_visited); + let reached_by = ReachedBy { + is_bound: enters, + is_checked, }; - self.assignment_target_in(target, enters); + self.assignment_target_in(target, reached_by); } return; } ExprKind::NonNull(x) | ExprKind::Assign { target: x, .. } => { - self.assignment_target_in(x, false); + let reached_by = ReachedBy { + is_bound: false, + is_checked, + }; + self.assignment_target_in(x, reached_by); + } + ExprKind::Ident(_) => { + self.assigned.push(e); + if !is_checked { + self.b.unchecked_assignment_targets.push(e); + } + } + ExprKind::Dot { .. } | ExprKind::Index { .. } if !is_checked => { + let mut root = e; + while let ExprKind::Dot { obj: x, .. } + | ExprKind::Index { obj: x, .. } + | ExprKind::NonNull(x) = self.f[root].kind + { + root = x; + } + if matches!(self.f[root].kind, ExprKind::Ident(_)) { + self.b.unchecked_assignment_targets.push(root); + } } - ExprKind::Ident(_) => self.assigned.push(e), // `(x as T) = v` is not an assignment to `x` as far as `GetAssignmentTarget` and // `isNarrowableReference` are concerned. _ => {} @@ -1260,12 +1321,17 @@ impl<'f, 's> Binder<'f, 's> { } /// `container.Symbol()` of the container whose scope is `scope`. `NONE` also where - /// `fn_symbol` is: such a symbol has no exports yet. + /// `fn_symbol` is, or where the object literal has no symbols: such a symbol has no exports + /// yet. fn symbol_of_container(&self, scope: ScopeId) -> SymbolId { let s = &self.b.scopes[scope.idx()]; match s.kind { - ScopeKind::Fn(f) => match self.b.fns[f.idx()].owner { - FnOwner::Member(m) => self.b.member_symbol[m.idx()], + ScopeKind::Fn(f) => match self.f.data(self.f.node(f)) { + NodeData::Member(m) => self.b.member_symbol[m.idx()], + NodeData::Prop(p) => { + let symbol = self.b.property_symbol.get(&Decl::Property(p)); + symbol.map_or(SymbolId::NONE, |&symbol| symbol) + } _ => self.b.fn_symbol[f.idx()], }, ScopeKind::Class(c) => self.b.class_symbol[c.idx()], @@ -1277,12 +1343,15 @@ impl<'f, 's> Binder<'f, 's> { /// `b.container.Symbol()` fn container_symbol(&mut self) -> SymbolId { let container = self.b.container_scope(self.scope); - if let ScopeKind::Fn(f) = self.b.scopes[container.idx()].kind - && matches!(self.f[f].kind, FnKind::Expr | FnKind::Arrow) - && self.b.fn_symbol[f.idx()].is_none() - { - let name = known::anonymous_function; - self.bind_anonymous_declaration(Decl::Fn(f), SymFlags::FUNCTION, name); + if let ScopeKind::Fn(f) = self.b.scopes[container.idx()].kind { + if let NodeData::Prop(method) = self.f.data(self.f.node(f)) { + self.symbol_of_literal_around(method); + } else if matches!(self.f[f].kind, FnKind::Expr | FnKind::Arrow) + && self.b.fn_symbol[f.idx()].is_none() + { + let name = known::anonymous_function; + self.bind_anonymous_declaration(Decl::Fn(f), SymFlags::FUNCTION, name); + } } self.symbol_of_container(container) } @@ -1507,19 +1576,6 @@ impl<'f, 's> Binder<'f, 's> { self.b.expando_declarations.as_mut_slice().sort_unstable(); } - /// `Resolve`: whether `f` has an `arguments` of its own. - fn has_arguments(&self, f: FnId) -> bool { - match self.f[f].kind { - FnKind::Decl | FnKind::Expr | FnKind::Getter | FnKind::Setter | FnKind::Constructor => { - true - } - // A method of a class or an object literal, not a method signature. - FnKind::Method => !matches!(self.b.fns[f.idx()].owner, FnOwner::Member(m) - if matches!(self.b.member_owner[m.idx()], MemberOwner::Interface(_) | MemberOwner::TypeLiteral(_))), - _ => false, - } - } - /// `Resolve` for the value `name`, among what the file declares, once everything is declared. /// `None`: `argumentsSymbol`. fn resolve(&self, mut scope: ScopeId, name: Atom) -> Option { @@ -1553,7 +1609,9 @@ impl<'f, 's> Binder<'f, 's> { if s.symbol.is_some() && name != known::default && let Some(&symbol) = tables[b.symbols[s.symbol.idx()].exports.idx()].get(&name) - && !b.symbols[symbol.idx()].flags.contains(SymFlags::EXPORT_ONLY) + // "purely an export specifier, it is not actually considered in scope" + && !(b.symbols[symbol.idx()].flags.contains(SymFlags::EXPORT_ONLY) + && b.is_external_module(self.f, scope)) // An export of a CommonJS module is only in scope inside the module if it is a // type. && !(s.kind == ScopeKind::File @@ -1581,7 +1639,7 @@ impl<'f, 's> Binder<'f, 's> { } if name == known::arguments && let ScopeKind::Fn(f) | ScopeKind::FunctionName(f) = s.kind - && self.has_arguments(f) + && b.has_arguments(self.f, f) { return None; } @@ -1604,7 +1662,7 @@ impl<'f, 's> Binder<'f, 's> { let kind = f.kind(node); match kind { Kind::Identifier => { - if f.text(node) == known::arguments && self.is_arguments_symbol_at(node) { + if self.is_named_arguments(node) && self.is_arguments_symbol_at(node) { return true; } } @@ -1651,6 +1709,21 @@ impl<'f, 's> Binder<'f, 's> { ) } + /// `node.Text() == c.argumentsSymbol.Name` for an identifier. The HIR has the text of a + /// `JsxNamespacedName` in one piece, `namespace:name`. + fn is_named_arguments(&self, node: Node) -> bool { + let f = self.f; + let half = match node.part() { + Some(Part::Namespace) => 0, + Some(Part::LocalName) => 1, + _ => return f.text(node) == known::arguments, + }; + let whole = f.text(f.parent(node)); + whole.is_some() + && (bun_core::strings::split(self.atoms.bytes(whole), b":").nth(half)) + .is_some_and(|text| text == b"arguments") + } + /// `c.IsArgumentsSymbol(c.getResolvedSymbol(node))` for an identifier named `arguments`. fn is_arguments_symbol_at(&mut self, node: Node) -> bool { if let NodeData::Expr(e) = self.f.data(node) { @@ -1667,10 +1740,11 @@ impl<'f, 's> Binder<'f, 's> { } /// The scope from which `Resolve` looks up `name`, an identifier that is not an expression. - fn scope_of_name(&self, name: Node) -> ScopeId { - let (f, b) = (self.f, &self.b); + fn scope_of_name(&mut self, name: Node) -> ScopeId { + let f = self.f; let (mut below, mut node) = (name, f.parent(name)); loop { + let b = &self.b; let scope = match f.data(node) { NodeData::None | NodeData::File => return ScopeId(0), // `Resolve` finds `arguments` at a method or an accessor wherever it comes from. @@ -1679,7 +1753,9 @@ impl<'f, 's> Binder<'f, 's> { { b.fns[f.function_of(node).idx()].scope } - NodeData::Member(m) => b.member_scope[m.idx()], + // "Decorators are resolved at the class declaration." + NodeData::Member(m) if f.kind(below) == Kind::Decorator => b.member_scope[m.idx()], + NodeData::Member(m) => self.scope_of_property_declaration(m), NodeData::EnumMember(m) => b.enum_scope[b.enum_member_owner[m.idx()].idx()], NodeData::TypeParam(p) => b.type_param_scope[p.idx()], NodeData::Expr(e) => match f[e].kind { @@ -1687,9 +1763,16 @@ impl<'f, 's> Binder<'f, 's> { ExprKind::Fn(func) => b.fns[func.idx()].scope, _ => ScopeId::NONE, }, - NodeData::Part(Part::CatchClause, row) => match f.data(row) { - NodeData::Stmt(s) => match f[s].kind { - StmtKind::Try { handler, .. } => b.stmt_scope[handler.idx()], + NodeData::Part(part, row) => match f.data(row) { + NodeData::Stmt(s) => match (part, f[s].kind) { + (Part::CatchClause, StmtKind::Try { handler, .. }) => { + b.stmt_scope[handler.idx()] + } + // The `CaseBlock`. One without a statement declares nothing. + (Part::Body, StmtKind::Switch { cases, .. }) => cases + .iter() + .find_map(|case| f.ids(f[case].body).next()) + .map_or(ScopeId::NONE, |first| b.stmt_scope[first.idx()]), _ => ScopeId::NONE, }, _ => ScopeId::NONE, @@ -1714,6 +1797,30 @@ impl<'f, 's> Binder<'f, 's> { } } + /// The scope of the name and the initializer of the member `m`. `members` makes a + /// `ScopeKind::PropertyDeclaration` around expressions only, and does not keep it. + fn scope_of_property_declaration(&mut self, m: MemberId) -> ScopeId { + let (around, owner) = (self.b.member_scope[m.idx()], self.b.member_owner[m.idx()]); + let constructor = match owner { + MemberOwner::Class(class) + if self.f[m].kind == MemberKind::Property && !self.is_static(m, owner) => + { + self.find_constructor_declaration(self.f[class].members) + } + _ => FnId::NONE, + }; + if constructor.is_none() || around.is_none() { + return around; + } + let current = std::mem::replace(&mut self.scope, around); + let scope = self.push_scope( + ScopeKind::PropertyDeclaration(m, constructor), + SymbolId::NONE, + ); + self.scope = current; + scope + } + fn finish(mut self) -> BoundBuilder { // Resolves names, now that everything is declared. let idents = std::mem::take(&mut self.idents); @@ -1755,6 +1862,10 @@ impl<'f, 's> Binder<'f, 's> { } } self.b.assignments.sort_unstable_by_key(|a| (a.0.0, a.1.0)); + let (expr_symbol, arguments_objects) = (&self.b.expr_symbol, &self.b.arguments_objects); + self.b.unchecked_assignment_targets.retain(|target| { + expr_symbol[target.idx()].is_none() && !arguments_objects.contains(target) + }); self.b.type_query_operands.as_mut_slice().sort_unstable(); self.b.unchecked_exprs.as_mut_slice().sort_unstable(); self.b.unchecked_types.as_mut_slice().sort_unstable(); @@ -1927,10 +2038,19 @@ impl<'f, 's> Binder<'f, 's> { StmtKind::Empty | StmtKind::Debugger => {} StmtKind::Expr(e) => { self.expr(e, me); - // `bindForStatement` binds its initializer, which is no `ExpressionStatement`. - let is_initializer_of_for = matches!(parent, Parent::Stmt(owner) - if matches!(self.f[owner].kind, StmtKind::For { init, .. } if init == id)); - if !is_initializer_of_for { + // `bindForStatement` binds its initializer and `bindEachChild` the object of a + // `with` statement. Neither is an `ExpressionStatement`. + let is_part_of_parent = matches!(parent, Parent::Stmt(owner) + if match self.f[owner].kind { + StmtKind::For { init, .. } => init == id, + StmtKind::Block(parts) => { + !self.f.with_bodies.is_empty() + && self.f.is_with_statement(owner) + && self.f.id_at(parts, 0) == id + } + _ => false, + }); + if !is_part_of_parent { self.maybe_call_flow(e); } } @@ -2148,6 +2268,15 @@ impl<'f, 's> Binder<'f, 's> { self.flow = self.finish_label(post); self.pop_scope(); } + // `GetContainerFlags` has no case for a `WithStatement`: it has no locals, and + // `bindEachChild` binds its object and then its statement. + StmtKind::Block(parts) + if !self.f.with_bodies.is_empty() && self.f.is_with_statement(id) => + { + for part in self.f.ids(parts) { + self.stmt(part, me); + } + } StmtKind::Block(list) => { self.push_scope(ScopeKind::Block, SymbolId::NONE); self.stmts(list, me); @@ -2412,7 +2541,9 @@ impl<'f, 's> Binder<'f, 's> { self.add_edge(post, self.flow); let has_default = cases.iter().any(|c| self.f[c].test.is_none()); if !has_default { - let none = if self.pre_switch != UNREACHABLE { + // `createFlowSwitchClause` makes a node also if the expression never completes. + // `bindChildren`: an unreachable statement is ignored. + let none = if self.is_reached { self.set_flow_node_referenced(self.pre_switch); self.new_flow(Flow::Switch { before: self.pre_switch, @@ -2545,7 +2676,7 @@ impl<'f, 's> Binder<'f, 's> { let is_augmentation = if is_at_top { self.f.has_module_syntax } else { - self.ambient_module_around().is_some() + self.ambient_module_around(self.scope).is_some() }; // `bindModuleDeclaration`: a module that is declared here is a value regardless of its // contents. @@ -2555,15 +2686,15 @@ impl<'f, 's> Binder<'f, 's> { } else { (SymFlags::NAMESPACE_MODULE, SymFlags::empty()) }; - // `declareSymbolAndAddToSymbolTable`: a declaration in a script, even inside a block, is - // global. - let is_global = !self.f.has_module_syntax - && matches!( - self.b.scopes[self.b.container_scope(self.scope).idx()].kind, - ScopeKind::File - ); + // `declareSymbolAndAddToSymbolTable`: the table is that of `b.container`, which a block is + // not. A declaration in a script, even inside a block, is global. + let container = self.b.container_scope(self.scope); + let is_in_file = matches!(self.b.scopes[container.idx()].kind, ScopeKind::File); + let is_global = is_in_file && !self.f.has_module_syntax; let symbol = match decl.name { - ModuleName::String(name) if is_global || is_augmentation => { + ModuleName::String(name) + if is_in_file || self.ambient_module_around(container).is_some() => + { // `collectModuleReferences`: a module augmentation must resolve its module, like an // import. At the top level of a script it declares the module itself. if !is_at_top { @@ -2573,14 +2704,13 @@ impl<'f, 's> Binder<'f, 's> { } // `declareSymbol(GetLocals(container), ..)`: one symbol in each container. let b = &self.b; - let container = b.container_scope(self.scope); let is_in_container = |symbol: SymbolId| { matches!(b.symbols[symbol.idx()].decls.first(), Some(&Decl::Module(first)) if b.container_scope(b.scopes[b.module_scope[first.idx()].idx()].parent) == container) }; let existing = (b.ambient_modules.iter()) - .find(|a| a.0 == name && a.2 == is_augmentation && is_in_container(a.1)) + .find(|a| a.0 == name && is_in_container(a.1)) .map(|a| a.1); match existing { Some(symbol) => { @@ -2589,8 +2719,7 @@ impl<'f, 's> Binder<'f, 's> { } None => { let symbol = self.bind_anonymous_declaration(Decl::Module(m), flags, name); - let module = (name, symbol, is_augmentation); - self.b.ambient_modules.push(module); + self.b.ambient_modules.push((name, symbol, is_global)); symbol } } @@ -3028,29 +3157,7 @@ impl<'f, 's> Binder<'f, 's> { fn func(&mut self, id: FnId, owner: FnOwner) { let f = &self.f[id]; self.b.fns[id.idx()].owner = owner; - // `NodeCanBeDecorated`: only a parameter of a class member can be decorated. Its decorators - // are bound with it. let is_class_member = matches!(owner, FnOwner::Member(m) if matches!(self.b.member_owner[m.idx()], MemberOwner::Class(_))); - if !is_class_member && !f.params.is_empty() && !self.f.decorators.is_empty() { - let counted = self.yields.len(); - // The state `leave_function_head` left for this function does not apply to a function - // inside a decorator. - let from_name = ( - std::mem::take(&mut self.this_in_name), - std::mem::replace(&mut self.flow_after_name, FlowId::NONE), - ); - for i in 0..self.f.decorators.len() { - let (of, e) = self.f.decorators[i]; - if let DecoratorOwner::Param(p) = of - && f.params.range().contains(&p.idx()) - { - self.expr(e, Parent::FnBody(id)); - self.b.refused_decorators.push(e); - } - } - (self.this_in_name, self.flow_after_name) = from_name; - self.yields.truncate(counted); - } // `Resolve`: the name of a function expression is searched after everything declared in the // function, including `arguments`. let has_own_name = f.kind == FnKind::Expr && f.name.is_some(); @@ -3063,12 +3170,21 @@ impl<'f, 's> Binder<'f, 's> { let saved_this = std::mem::replace(&mut self.seen_this, std::mem::take(&mut self.this_in_name)); let outer_member = std::mem::replace(&mut self.cur_member, MemberId::NONE); - let outer_this = self.this_member; + let outer_this = (self.this_member, self.this_property); if f.kind != FnKind::Arrow { self.this_member = match owner { FnOwner::Member(m) if is_class_member => m, _ => MemberId::NONE, }; + self.this_property = match (owner, f.kind) { + (FnOwner::Expr(e), FnKind::Method | FnKind::Getter | FnKind::Setter) => { + match self.b.expr_parent[e.idx()] { + Parent::Prop(p) => p, + _ => PropId::NONE, + } + } + _ => PropId::NONE, + }; } // `requiresScopeChangeWorker` does not descend into functions, but visits a static block // like any statement. @@ -3187,11 +3303,14 @@ impl<'f, 's> Binder<'f, 's> { let param = &self.f[p]; // `bindParameterFlow`: the modifiers come first. let modifiers = self.f.param_modifiers(p); - if let FnOwner::Member(m) = owner - && let MemberOwner::Class(class) = self.b.member_owner[m.idx()] - && self.has_decorators(modifiers) - { - self.decorators_in_member(modifiers, class, m, DecoratorOwner::Param(p)); + if self.has_decorators(modifiers) { + if let FnOwner::Member(m) = owner + && let MemberOwner::Class(class) = self.b.member_owner[m.idx()] + { + self.decorators_in_member(modifiers, class, m, DecoratorOwner::Param(p)); + } else { + self.decorators_outside_class(modifiers, id, scope); + } } if param.ty.is_some() { self.ty(param.ty); @@ -3298,7 +3417,7 @@ impl<'f, 's> Binder<'f, 's> { }; self.seen_this = saved_this || propagates && self.seen_this; self.cur_member = outer_member; - self.this_member = outer_this; + (self.this_member, self.this_property) = outer_this; self.scope_change_of = outer_scope_change; self.associated_declaration = outer_associated; ( @@ -3329,6 +3448,8 @@ impl<'f, 's> Binder<'f, 's> { fn class(&mut self, id: ClassId, owner: ClassOwner) { let c = &self.f[id]; self.b.class_owner[id.idx()] = owner; + self.containing_classes.push(id); + let in_class_decorator = std::mem::replace(&mut self.is_in_class_decorator, false); // `Resolve`, `KindDecorator`: only from a decorator of a class declaration does the search // skip the class. A decorator of a class expression sees its name and type parameters. if let ClassOwner::Stmt(_) = owner { @@ -3393,12 +3514,15 @@ impl<'f, 's> Binder<'f, 's> { if has_own_name { self.pop_scope(); } + self.is_in_class_decorator = in_class_decorator; + self.containing_classes.pop(); } /// The decorators among `modifiers`, which are the modifiers of `of`: `class`, a member of it /// or a parameter of a member. fn decorators(&mut self, modifiers: Span, class: ClassId, of: DecoratorOwner) { let owner = self.b.class_owner[class.idx()]; + self.is_in_class_decorator = matches!(of, DecoratorOwner::Class(_)); for modifier in modifiers.iter() { if let ModifierKind::Decorator(e) = self.f[modifier].kind { self.expr(e, Parent::Decorator(class, of)); @@ -3407,6 +3531,7 @@ impl<'f, 's> Binder<'f, 's> { } } } + self.is_in_class_decorator = false; } /// The decorators of the member `m` of `class`, or of its parameter `of`. `Resolve`, @@ -3435,6 +3560,38 @@ impl<'f, 's> Binder<'f, 's> { self.scope = around; } + /// The decorators among `modifiers`, those of a parameter of `func`, which is no member of a + /// class: `NodeCanBeDecorated` is false. `function_scope`: the scope of `func`. `Resolve`, + /// `KindDecorator`: the search goes on at the parameter, but around a function whose kind is + /// that of a class element (`IsClassElement`): a method of an object literal, an accessor, an + /// index signature. + fn decorators_outside_class( + &mut self, + modifiers: Span, + func: FnId, + function_scope: ScopeId, + ) { + let is_class_element = match self.f[func].kind { + FnKind::Getter | FnKind::Setter | FnKind::IndexSignature => true, + FnKind::Method => matches!(self.b.fns[func.idx()].owner, FnOwner::Expr(_)), + _ => false, + }; + let around = self.scope; + if is_class_element { + self.scope = self.b.scopes[function_scope.idx()].parent; + } + // `forEachYieldExpression` visits the body of a function only. + let counted = self.yields.len(); + for modifier in modifiers.iter() { + if let ModifierKind::Decorator(e) = self.f[modifier].kind { + self.expr(e, Parent::FnBody(func)); + self.b.refused_decorators.push(e); + } + } + self.yields.truncate(counted); + self.scope = around; + } + /// `NodeCanBeDecorated` fn can_be_decorated(&self, of: DecoratorOwner, class: ClassId, owner: ClassOwner) -> bool { let legacy = self.f.legacy_decorators; @@ -3501,21 +3658,28 @@ impl<'f, 's> Binder<'f, 's> { } } + /// `FindConstructorDeclaration`, for `ScopeKind::PropertyDeclaration`: none either if class + /// fields are emitted unchanged. + fn find_constructor_declaration(&self, members: Span) -> FnId { + if self.options.emit_standard_class_fields { + return FnId::NONE; + } + members + .iter() + .find(|&m| { + self.f[m].kind == MemberKind::Constructor + && !matches!(self.f[self.f[m].func].body, FnBody::None) + }) + .map_or(FnId::NONE, |m| self.f[m].func) + } + fn members(&mut self, members: Span, owner: MemberOwner) { let is_in_class_expression = matches!(owner, MemberOwner::Class(c) if matches!(self.b.class_owner[c.idx()], ClassOwner::Expr(_))); - // `FindConstructorDeclaration`, for `ScopeKind::PropertyDeclaration`. - let constructor = - if matches!(owner, MemberOwner::Class(_)) && !self.options.emit_standard_class_fields { - members - .iter() - .find(|&m| { - self.f[m].kind == MemberKind::Constructor - && !matches!(self.f[self.f[m].func].body, FnBody::None) - }) - .map_or(FnId::NONE, |m| self.f[m].func) - } else { - FnId::NONE - }; + let constructor = if matches!(owner, MemberOwner::Class(_)) { + self.find_constructor_declaration(members) + } else { + FnId::NONE + }; // `b.container.Symbol()` let container = match owner { MemberOwner::Class(c) => self.b.class_symbol[c.idx()], @@ -3581,7 +3745,7 @@ impl<'f, 's> Binder<'f, 's> { self.exception_target = FlowId::NONE; } // `ContainerFlagsIsThisContainer` - let outer_this = self.this_member; + let outer_this = (self.this_member, self.this_property); if is_initialized_property || class.is_some() && matches!( @@ -3593,7 +3757,7 @@ impl<'f, 's> Binder<'f, 's> { | MemberKind::StaticBlock ) { - self.this_member = m; + (self.this_member, self.this_property) = (m, PropId::NONE); } // `bindEachChild`: the decorators and the name are the first children of the member. let has_decorators = class.is_some() && self.has_decorators(member.modifiers); @@ -3613,11 +3777,13 @@ impl<'f, 's> Binder<'f, 's> { } if let PropKey::Computed(key) = member.key { // `checkComputedPropertyName`: `[P in K]` outside a mapped type is an error of its own and is not checked. + // `checkIndexConstraints` checks that of a class member. let around = self.is_unchecked; self.is_unchecked |= matches!(self.f[key].kind, ExprKind::Binary { op: BinOp::In, .. }) && !is_parenthesized(self.f, key) - && !matches!(member.kind, MemberKind::Getter | MemberKind::Setter); + && !matches!(member.kind, MemberKind::Getter | MemberKind::Setter) + && !matches!(owner, MemberOwner::Class(_)); let is_of_class_or_interface = matches!(owner, MemberOwner::Class(_) | MemberOwner::Interface(_)); if is_of_class_or_interface { @@ -3705,7 +3871,7 @@ impl<'f, 's> Binder<'f, 's> { self.pop_scope(); } self.cur_member = outer_member; - self.this_member = outer_this; + (self.this_member, self.this_property) = outer_this; } } @@ -3847,14 +4013,15 @@ impl<'f, 's> Binder<'f, 's> { } self.tys(args) } - // The checker reports it (2499, 2500) and does not check it. - TypeNodeKind::Heritage(expr) => { + // The checker reports it (2499, 2500) and does not check the expression. + TypeNodeKind::Heritage { expr, args } => { let parent = self.parent_of_expression_in_type(); let saved = (self.true_target, self.false_target); (self.true_target, self.false_target) = (FlowId::NONE, FlowId::NONE); self.b.expr_scope.insert(expr, self.scope); self.unchecked_expr(expr, parent); (self.true_target, self.false_target) = saved; + self.tys(args) } TypeNodeKind::Typeof { args, expr, .. } => { let parent = self.parent_of_expression_in_type(); @@ -4041,21 +4208,20 @@ impl<'f, 's> Binder<'f, 's> { } /// `lookupSymbolForPrivateIdentifierDeclaration`: the innermost enclosing class that declares - /// `#name`, static or not. + /// `#name`, static or not. `getContainingClassExcludingClassDecorators`: only the search that + /// starts in a decorator of a class skips that class. fn private_name(&mut self, id: ExprId, name: Atom) { - let mut scope = self.scope; - while scope.is_some() { - let s = &self.b.scopes[scope.idx()]; - if let ScopeKind::Class(class) = s.kind - && self.f[class] - .members - .iter() - .any(|m| self.f[m].key == PropKey::Private(name)) - { - self.b.private_class.insert(id, class); - return; - } - scope = s.parent; + let searched = self.containing_classes.len() - usize::from(self.is_in_class_decorator); + let declares = |class: &&ClassId| { + let mut members = self.f[**class].members.iter(); + members.any(|m| self.f[m].key == PropKey::Private(name)) + }; + if let Some(&class) = self.containing_classes[..searched] + .iter() + .rev() + .find(declares) + { + self.b.private_class.insert(id, class); } } @@ -4449,6 +4615,11 @@ impl<'f, 's> Binder<'f, 's> { self.expr(value, me); } } + // `TypeAssertion.ForEachChild`: `e` has its type first. + ExprKind::As { expr, ty } if self.f.is_type_assertion(id, expr) => { + self.ty(ty); + self.expr(expr, me); + } ExprKind::As { expr, ty } | ExprKind::Satisfies { expr, ty } => { self.expr(expr, me); self.ty(ty); @@ -4492,26 +4663,57 @@ impl<'f, 's> Binder<'f, 's> { } } - /// `bindThisPropertyAssignment`, `getThisClassAndSymbolTable` + /// `getThisClassAndSymbolTable` + fn get_this_class_and_symbol_table(&mut self) -> Option<(SymbolId, TableId)> { + let (class, is_static) = if self.this_property.is_some() { + let is_static = self.f.is_static(self.f.node(self.this_property)); + (self.symbol_of_literal_around(self.this_property), is_static) + } else if self.this_member.is_some() + && let MemberOwner::Class(c) = self.b.member_owner[self.this_member.idx()] + { + let member = &self.f[self.this_member]; + let is_static = + member.flags.contains(Flags::STATIC) || member.kind == MemberKind::StaticBlock; + (self.b.class_symbol[c.idx()], is_static) + } else { + return None; + }; + let table = if is_static { + self.get_exports(class) + } else { + self.get_members(class) + }; + Some((class, table)) + } + + /// `node.Symbol()` of the object literal whose member `p` is being bound. A literal without a + /// symbol gets it on this request, with the members that are declared by now: those up to `p`. + fn symbol_of_literal_around(&mut self, p: PropId) -> SymbolId { + let literal = self.b.prop_owner[p.idx()]; + if self.b.expr_symbol[literal.idx()].is_none() { + let container = self.bind_object_literal(literal); + if let ExprKind::Object(props) = self.f[literal].kind { + for declared in props.iter().take_while(|&declared| declared <= p) { + self.bind_literal_member(container, declared); + } + } + } + self.b.expr_symbol[literal.idx()] + } + + /// `bindThisPropertyAssignment` fn bind_this_property_assignment(&mut self, e: ExprId) { let decl = Decl::ThisProperty(e); - if self.this_member.is_none() + if self.this_member.is_none() && self.this_property.is_none() || assignment_declaration_kind(self.f, e) != JsDeclarationKind::ThisProperty || matches!(self.f[e].kind, ExprKind::Assign { target, .. } if matches!(self.f[target].kind, ExprKind::Dot { name_pos, .. } if is_private_name_at(self.f, name_pos))) { return; } - let MemberOwner::Class(c) = self.b.member_owner[self.this_member.idx()] else { + let Some((class, table)) = self.get_this_class_and_symbol_table() else { return; }; - let (class, member) = (self.b.class_symbol[c.idx()], &self.f[self.this_member]); - let table = - if member.flags.contains(Flags::STATIC) || member.kind == MemberKind::StaticBlock { - self.get_exports(class) - } else { - self.get_members(class) - }; let mut flags = SymFlags::PROPERTY | SymFlags::ASSIGNMENT; let mut is_computed_name = IsComputedName::No; // `HasDynamicName`. `node.Symbol` ends up as the symbol declared last. @@ -4576,9 +4778,40 @@ impl<'f, 's> Binder<'f, 's> { (chain != Chain::No).then_some((inner, chain == Chain::Start)) } + /// `isTopLevelLogicalExpression`. `enter_expr` records the parents. + fn is_top_level_logical_expression(&self, mut node: ExprId) -> bool { + while let Parent::Expr(parent) = self.b.expr_parent[node.idx()] + && matches!(self.f[parent].kind, ExprKind::Unary { op: UnOp::Not, .. }) + { + node = parent; + } + match self.b.expr_parent[node.idx()] { + // `isStatementCondition` + Parent::Stmt(statement) => !matches!( + self.f[statement].kind, + StmtKind::If { test, .. } + | StmtKind::While { test, .. } + | StmtKind::DoWhile { test, .. } + | StmtKind::For { test, .. } if test == node + ), + Parent::Expr(parent) => match self.f[parent].kind { + ExprKind::Cond { test, .. } => test != node, + // `IsLogicalExpression`, which `a ??= b` is not. + ExprKind::Binary { + op: BinOp::And | BinOp::Or | BinOp::Nullish, + .. + } => false, + _ => self + .chain_of(parent) + .is_none_or(|(expression, _)| expression != node), + }, + _ => true, + } + } + /// `bindOptionalChainFlow` fn optional_chain_flow(&mut self, id: ExprId, parent: Parent, targets: (FlowId, FlowId)) { - if targets.0.is_some() { + if !self.is_top_level_logical_expression(id) { return self.optional_chain(id, parent, targets.0, targets.1); } let post = self.branch_label(); @@ -4693,7 +4926,7 @@ impl<'f, 's> Binder<'f, 's> { targets: (FlowId, FlowId), is_assignment: bool, ) { - let top_level = targets.0.is_none(); + let top_level = self.is_top_level_logical_expression(id); let post = if top_level { self.branch_label() } else { @@ -4728,11 +4961,15 @@ impl<'f, 's> Binder<'f, 's> { } else { (on.0, pre_right) }; - let ExprKind::Binary { - op: op @ (BinOp::And | BinOp::Or | BinOp::Nullish), - left, - right, - } = self.f[operands.0].kind + // The left operand of `a ??= b` is top level, and binds to a label of its own. + let ( + ExprKind::Binary { .. }, + ExprKind::Binary { + op: op @ (BinOp::And | BinOp::Or | BinOp::Nullish), + left, + right, + }, + ) = (self.f[node].kind, self.f[operands.0].kind) else { self.condition(operands.0, Parent::Expr(node), on.0, on.1); break; @@ -4776,27 +5013,40 @@ impl<'f, 's> Binder<'f, 's> { } } + /// `bindAnonymousDeclaration(node, SymbolFlagsObjectLiteral, InternalSymbolNameObject)` + fn bind_object_literal(&mut self, literal: ExprId) -> SymbolId { + let (decl, flags) = (Decl::ObjectLiteral(literal), SymFlags::OBJECT_LITERAL); + let container = self.bind_anonymous_declaration(decl, flags, known::object_literal); + self.get_members(container); + container + } + + /// `bindPropertyOrMethodOrAccessor` for the member `p` of the literal whose symbol is `container`. + fn bind_literal_member(&mut self, container: SymbolId, p: PropId) { + if let Some((includes, excludes)) = flags_of_property(self.f[p].kind) { + let members = self.get_members(container); + self.declare_symbol(members, container, Decl::Property(p), includes, excludes); + } + } + fn props(&mut self, props: Span, owner: ExprId) { - // Only where a name occurs twice or is computed: `PropSource::Literal` is the symbol of any - // other. + // Only where a name occurs twice or is computed, or `symbol_of_literal_around` asks for it: + // `PropSource::Literal` is the symbol of any other. let names: SmallVec<[PropKey; 16]> = props.iter().map(|p| self.f[p].key).collect(); let written = names.iter().filter_map(|key| key.name()); if names.iter().any(|key| matches!(key, PropKey::Computed(_))) || !number_repeated(&written.collect::>()).is_empty() { - let (decl, flags) = (Decl::ObjectLiteral(owner), SymFlags::OBJECT_LITERAL); - let container = self.bind_anonymous_declaration(decl, flags, known::object_literal); - let members = self.get_members(container); - for p in props.iter() { - if let Some((includes, excludes)) = flags_of_property(self.f[p].kind) { - self.declare_symbol(members, container, Decl::Property(p), includes, excludes); - } - } + self.bind_object_literal(owner); } let in_pattern = self.in_assignment_pattern; let is_literal = matches!(self.f[owner].kind, ExprKind::Object(_)); for p in props.iter() { self.b.prop_owner[p.idx()] = owner; + let container = self.b.expr_symbol[owner.idx()]; + if container.is_some() { + self.bind_literal_member(container, p); + } self.jsdoc_type(JsDocTypeOwner::Prop(p)); let prop = &self.f[p]; self.note_private_name(Decl::Property(p), prop.key); @@ -4809,12 +5059,13 @@ impl<'f, 's> Binder<'f, 's> { let method = self.f.function_of(self.f.node(p)); if method.is_some() { let head = self.enter_function_head(true); - // `thisContainer` is the method, which is no member of a class. - let outer_this = std::mem::replace(&mut self.this_member, MemberId::NONE); + // `thisContainer` is the method. + let outer_this = (self.this_member, self.this_property); + (self.this_member, self.this_property) = (MemberId::NONE, p); self.push_scope(ScopeKind::FunctionName(method), SymbolId::NONE); self.expr(key, Parent::MethodKey(p)); self.pop_scope(); - self.this_member = outer_this; + (self.this_member, self.this_property) = outer_this; self.leave_function_head(head); } else { self.expr( diff --git a/src/sema/bind/mod.rs b/src/sema/bind/mod.rs index 998ee932b17f..46557c68dd01 100644 --- a/src/sema/bind/mod.rs +++ b/src/sema/bind/mod.rs @@ -143,7 +143,8 @@ pub enum Decl { Member(MemberId), /// `IsParameterPropertyDeclaration`: the property. ParameterProperty(ParamId), - /// `this.name = value` in a member of a class, in JavaScript: the assignment. + /// `this.name = value` in a member of a class, or in a method or an accessor of an object + /// literal, in JavaScript: the assignment. ThisProperty(ExprId), /// A member of an object literal or an attribute of a JSX element. Property(PropId), @@ -676,6 +677,16 @@ impl PatParent { PatParent::None => ExprId::NONE, } } + + /// `hasDotDotDotToken` of the binding element. + #[inline] + pub fn has_dot_dot_dot_token(self, hir: &File) -> bool { + match self { + PatParent::Prop(_, prop) => hir[prop].is_rest, + PatParent::Elem(_, elem) => hir[elem].is_rest, + PatParent::Var(_) | PatParent::Param(_) | PatParent::None => false, + } + } } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -693,6 +704,15 @@ impl ClassOwner { ClassOwner::Stmt(s) => Parent::Stmt(s), } } + + /// `node.End()` of the class. 0: the binder did not reach it. + #[inline] + pub fn end(self, hir: &File) -> u32 { + match self { + ClassOwner::Expr(e) => hir[e].end, + ClassOwner::Stmt(s) => hir.stmts.get(s.idx()).map_or(0, |class| class.loc.end), + } + } } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -840,10 +860,10 @@ pub struct BoundIn { /// `exportStars.Declarations`: every `export * from spec`, with the module or namespace symbol /// that contains it. pub export_stars: S::Few<(SymbolId, StmtId)>, - /// `declare module "name"` at the top level of a file, or directly inside an ambient module at - /// the top level of a script. The flag is `IsModuleAugmentationExternal`: it augments a module - /// that is declared elsewhere. One entry for each symbol, which the declarations of a name in - /// one container share. + /// `declare module "name"` whose container is the file, or an ambient module at the top level + /// of a script. One entry for each symbol, which the declarations of a name in one container + /// share. The flag: it is a local of a file without module syntax, where it declares the + /// module. Any other is merged by `mergeModuleAugmentation` or not at all. pub ambient_modules: S::Few<(Atom, SymbolId, bool)>, /// `file.PatternAmbientModules`: a module whose name has exactly one `*` and that augments /// nothing, wherever it is declared. One entry for each declaration. @@ -936,6 +956,10 @@ pub struct BoundIn { pub var_stmt: S::List, /// The identifiers that are assigned to, keyed by the variable they resolve to. pub assignments: S::List<(SymbolId, ExprId)>, + /// The identifiers that are assigned to, or whose property is, that nothing in this file + /// declares, and that `checkDestructuringAssignment` does not get to: it returns at a rest + /// element that is not the last (2462) or that has an initializer (1186). + pub unchecked_assignment_targets: S::Few, /// The expressions that are (part of) the operand of a `typeof` in a type. Sorted. pub type_query_operands: S::Few, /// The expressions at or under a node that is in tsgo's AST but that `checkSourceFile` never @@ -949,6 +973,9 @@ pub struct BoundIn { pub infer_positions: S::Few<(TypeParamId, InferPosition)>, /// The assignments and calls that `bindDeferredExpandoAssignment` gives a symbol. Sorted. pub expando_declarations: S::Few, + /// The symbol of each `this[k] = v` with a dynamic name, and the table it is declared in, in + /// the order they are bound. See `computed_symbol_in_table`. + pub computed_symbols: S::Few<(TableId, SymbolId)>, pub case_stmt: S::List, /// The flow node at the start of each statement. pub stmt_flow: S::List, @@ -1186,6 +1213,40 @@ impl BoundIn { &self.entries[start as usize..(start + len) as usize] } + /// `NameResolver.Resolve`: `IsSourceFile(location) || IsModuleDeclaration(location) && + /// location.Flags&NodeFlagsAmbient != 0 && !IsGlobalScopeAugmentation(location)`, where `scope` + /// is that of `location`. + pub fn is_external_module(&self, hir: &File, scope: ScopeId) -> bool { + match self.scopes[scope.idx()].kind { + ScopeKind::File => true, + ScopeKind::Module(m) => { + let mut around = std::iter::successors(Some(scope), |&at| { + Some(self.scopes[at.idx()].parent).filter(|parent| parent.is_some()) + }); + !matches!(hir[m].name, ModuleName::Global) + && (hir.kind == FileKind::Declaration + || around.any(|at| { + matches!(self.scopes[at.idx()].kind, ScopeKind::Module(it) + if hir[it].flags.contains(Flags::AMBIENT)) + })) + } + _ => false, + } + } + + /// `NameResolver.Resolve`: whether `func` has an `arguments` of its own. + pub fn has_arguments(&self, hir: &File, func: FnId) -> bool { + match hir[func].kind { + FnKind::Decl | FnKind::Expr | FnKind::Getter | FnKind::Setter | FnKind::Constructor => { + true + } + // A method of a class or an object literal, not a method signature. + FnKind::Method => !matches!(self.fns[func.idx()].owner, FnOwner::Member(m) + if matches!(self.member_owner[m.idx()], MemberOwner::Interface(_) | MemberOwner::TypeLiteral(_))), + _ => false, + } + } + /// `NameResolver.Resolve`, the restrictions on the locals of a function and of a conditional /// type: whether a local with `flags` is visible to a lookup for `meaning` that has just left a /// scope of kind `from`. @@ -1438,6 +1499,16 @@ impl Bound<'_> { self.expando_declarations.binary_search(&e).is_ok() } + /// `symbolTable["__computed"]`, which every `this[k] = v` of one table declares, so that its + /// `ValueDeclaration` is the first of them. Here each has its own `symbol`: that of the first. + pub fn computed_symbol_in_table(&self, symbol: SymbolId) -> SymbolId { + let Some(&(table, _)) = self.computed_symbols.iter().find(|it| it.1 == symbol) else { + return symbol; + }; + let first = self.computed_symbols.iter().find(|it| it.0 == table); + first.map_or(symbol, |it| it.1) + } + /// `node.Symbol`. `NONE`: it is not stored for a declaration of that kind, none of which has a /// local symbol. pub fn symbol_of_declaration(&self, decl: Decl) -> SymbolId { @@ -1463,6 +1534,15 @@ impl Bound<'_> { } } + /// `node.Symbol` of the function-like `f`. + pub fn symbol_of_function(&self, hir: &File, f: FnId) -> SymbolId { + self.symbol_of_declaration(match hir.data(hir.node(f)) { + NodeData::Member(m) => Decl::Member(m), + NodeData::Prop(p) => Decl::Property(p), + _ => Decl::Fn(f), + }) + } + /// The scope at which `FindAncestor` from `decl` starts: the scope that a file, a module or a /// namespace creates, and the enclosing scope of any other declaration. `NONE`: the binder did /// not reach it, or it is an assignment. @@ -1613,6 +1693,21 @@ impl Bound<'_> { .intersects(SymFlags::VALUE) .then_some((code, property)) } + + /// `NameResolver.Resolve`: whether a lookup of the variable `arguments` from `scope` that finds + /// no declaration ends at `argumentsSymbol`, which is in no table. + pub fn is_in_function_with_arguments(&self, hir: &File, mut scope: ScopeId) -> bool { + while scope.is_some() { + let s = &self.scopes[scope.idx()]; + if let ScopeKind::Fn(f) | ScopeKind::FunctionName(f) = s.kind + && self.has_arguments(hir, f) + { + return true; + } + scope = s.parent; + } + false + } } fn map_to_arena<'s, K: Eq + std::hash::Hash, V>( @@ -1704,11 +1799,13 @@ impl BoundBuilder { module_instance_state: few_to_arena(self.module_instance_state, arena), var_stmt: copy_to_arena(&mut self.var_stmt, arena), assignments: copy_to_arena(&mut self.assignments, arena), + unchecked_assignment_targets: few_to_arena(self.unchecked_assignment_targets, arena), type_query_operands: few_to_arena(self.type_query_operands, arena), unchecked_exprs: few_to_arena(self.unchecked_exprs, arena), unchecked_types: few_to_arena(self.unchecked_types, arena), infer_positions: few_to_arena(self.infer_positions, arena), expando_declarations: few_to_arena(self.expando_declarations, arena), + computed_symbols: few_to_arena(self.computed_symbols, arena), case_stmt: copy_to_arena(&mut self.case_stmt, arena), stmt_flow: copy_to_arena(&mut self.stmt_flow, arena), case_fallthrough: copy_to_arena(&mut self.case_fallthrough, arena), diff --git a/src/sema/check/alias.rs b/src/sema/check/alias.rs index bee463207c3b..f80261816218 100644 --- a/src/sema/check/alias.rs +++ b/src/sema/check/alias.rs @@ -29,20 +29,42 @@ impl<'p, 's> Checker<'p, 's> { } } - /// `getUnionTypeFromSortedList`: the members of `union`, with `origin` and no alias. - pub(super) fn with_origin(&self, union: TypeId, origin: OriginKey<'_>) -> TypeId { + /// The type of `key` with `alias` as `Type.alias` and `origin` as `UnionType.origin`. + pub(super) fn intern_key_with_alias( + &self, + key: TypeKey<'_>, + alias: Option<(Sym, &[TypeId])>, + origin: OriginKey<'_>, + ) -> TypeId { + let is_enum = + alias.is_some_and(|(alias, _)| self.files().flags(alias).intersects(SymFlags::ENUM)); + // `!isNonGenericTopLevelType` + let has_other_instantiation = alias.is_some_and(|(alias, type_arguments)| { + type_arguments.is_empty() + && self + .types() + .has_constituent_with_other_instantiation(key, origin) + && !self.is_non_generic_top_level_alias(alias) + }); self.types().intern_key_with( - TypeKey::Data(self.data(union)), + key, &ProvenanceKey { - alias: None, + alias, origin, - is_enum: false, + is_enum, stored_under: None, is_array_literal: false, + is_array_pattern: false, + has_other_instantiation, }, ) } + /// `getUnionTypeFromSortedList`: the members of `union`, with `origin` and no alias. + pub(super) fn with_origin(&self, union: TypeId, origin: OriginKey<'_>) -> TypeId { + self.intern_key_with_alias(TypeKey::Data(self.data(union)), None, origin) + } + /// The alias stored in `ty`. #[inline] pub(super) fn stored_alias(&self, ty: TypeId) -> Option<&'p (Sym, ArenaBox<'p, [TypeId]>)> { @@ -51,16 +73,8 @@ impl<'p, 's> Checker<'p, 's> { /// `ty` with `alias` and `type_arguments` as `Type.alias`. pub(super) fn with_alias(&self, ty: TypeId, alias: Sym, type_arguments: &[TypeId]) -> TypeId { - self.types().intern_key_with( - TypeKey::Data(self.data(ty)), - &ProvenanceKey { - alias: Some((alias, type_arguments)), - origin: self.origin(ty).into(), - is_enum: self.files().flags(alias).intersects(SymFlags::ENUM), - stored_under: None, - is_array_literal: false, - }, - ) + let key = TypeKey::Data(self.data(ty)); + self.intern_key_with_alias(key, Some((alias, type_arguments)), self.origin(ty).into()) } /// The end of `getUnionTypeWorker`, given an alias. `created` is the union without one. A named @@ -85,12 +99,16 @@ impl<'p, 's> Checker<'p, 's> { return self.with_alias(created, alias, type_arguments); } let origin = [created]; + let could_contain_type_variables = !self.is_non_generic_top_level_alias(alias) + && (self.parts(created).iter()).any(|&t| self.could_contain_type_variables(t)); let provenance = ProvenanceKey { alias: Some((alias, type_arguments)), origin: OriginKey::Union(&origin), is_enum: false, stored_under: None, is_array_literal: false, + is_array_pattern: false, + has_other_instantiation: could_contain_type_variables, }; (self.types()).intern_key_with(TypeKey::Data(self.data(created)), &provenance) } @@ -299,13 +317,7 @@ impl<'p, 's> Checker<'p, 's> { mapper: MapperId, alias: (Sym, &[TypeId]), ) -> TypeId { - if !self.has_type_variables(ty) - && !self.stored_alias(ty).is_some_and(|own| { - own.1 - .iter() - .any(|&argument| self.has_type_variables(argument)) - }) - { + if !self.types().get_for_instantiation(ty).1 { return ty; } if self.hands_out_symbol_ids() { @@ -421,7 +433,11 @@ impl<'p, 's> Checker<'p, 's> { }; let new = self.instantiate_all(types, mapper); let own = self.stored_alias(ty); - if new[..] == *types && alias.map(|alias| alias.0) == own.map(|own| own.0) { + // A declared type has no mapper in tsgo. Here it has one of identity pairs. + if new[..] == *types + && (alias.map(|alias| alias.0) == own.map(|own| own.0) + || alias.is_none() && !self.is_instantiating(mapper)) + { return ty; } let instantiated; diff --git a/src/sema/check/call.rs b/src/sema/check/call.rs index 26e82c46edeb..ac588ef1a1a7 100644 --- a/src/sema/check/call.rs +++ b/src/sema/check/call.rs @@ -265,6 +265,14 @@ impl<'p, 's> Checker<'p, 's> { stored: Stored, ) -> ResolvedCall { let key = (file, call); + if self.task.file == Some(file) { + if self.serialization_level >= super::sink::MAX_SERIALIZATION_LEVEL { + self.signatures_resolved_discarding.push(call); + } else { + // A resolution around the one that was the first to assign has reported. + self.signatures_resolved_discarding.retain(|&it| it != call); + } + } ResolvedCall { ret: (self.p.call_return_types).insert(&self.task, key, resolved.ret, stored), sig: self.p.calls.insert(&self.task, key, resolved.sig, stored), @@ -549,7 +557,11 @@ impl<'p, 's> Checker<'p, 's> { } /// `hasCorrectArity` - pub(super) fn has_correct_arity(&mut self, s: &CallState<'_>, params: &[SigParam]) -> bool { + pub(super) fn has_correct_arity( + &mut self, + s: &CallState<'_>, + params: &List<'_, SigParam>, + ) -> bool { let (file, call, node, args) = (s.file, s.call, s.node, s.args); // The attributes are a single argument, regardless of the component's other parameters. if matches!(node, CallLike::Jsx(_)) { @@ -561,21 +573,27 @@ impl<'p, 's> Checker<'p, 's> { }; let spread = args.iter().position(|a| a.is_spread()); let is_incomplete = self.is_call_incomplete(file, call, node); - self.has_correct_arity_for_count(params, actual, spread, is_incomplete) + let is_open = matches!(params, List::Own(_)); + self.has_correct_arity_for_count(params, is_open, actual, spread, is_incomplete) } /// `hasCorrectArity` for a call with `actual` arguments. `spread`: the first spread argument. - pub(super) fn has_correct_arity_for_count( + /// `is_open`: `sig_params` could not store `params`, so a cycle through the type of a parameter + /// is found where tsgo asks for that type. + fn has_correct_arity_for_count( &mut self, params: &[SigParam], + is_open: bool, actual: usize, spread: Option, is_incomplete: bool, ) -> bool { // Which parameters accept `void` only matters where a required one is omitted. That - // `getMinArgumentCount` asks only matters for `get_type_of_parameter` of a pattern. + // `getMinArgumentCount` asks only matters for `get_type_of_parameter` of a pattern, and + // where `is_open`. let rest = params.last().filter(|p| p.rest); - if spread.is_none() + if !is_open + && spread.is_none() && !rest.is_some_and(|p| self.is_tuple(p.ty)) && !params.iter().any(SigParam::is_named_by_pattern) { @@ -589,6 +607,15 @@ impl<'p, 's> Checker<'p, 's> { } let count = self.parameter_count(params); let least = self.min_argument_count(params); + if is_open { + // `getParameterCount`, then `getMinArgumentCount`: from the last required parameter + // down to one that does not accept `void`. + let required = ¶ms[..Self::min_args(params)]; + let asked = required.iter().skip(least.saturating_sub(1)).rev(); + for param in rest.into_iter().chain(asked) { + self.request_type_of_parameter(param); + } + } let has_rest = self.has_effective_rest_parameter(params); // The spread argument comes after all required parameters, and either reaches a rest // parameter or at least starts within the parameter list. @@ -604,6 +631,9 @@ impl<'p, 's> Checker<'p, 's> { // `acceptsVoid`: only a parameter that accepts `void` may be omitted. For a parameter whose // type is not known this cannot be determined. for i in actual..least { + if is_open && let Some(param) = params.get(i) { + self.request_type_of_parameter(param); + } let Some(ty) = self.param_type_at(params, i) else { return false; }; @@ -710,7 +740,11 @@ impl<'p, 's> Checker<'p, 's> { // (`checkExpression`), which has no re-entrancy guard. let outer = (self.resolution_start != self.stack.len()).then(|| self.begin_recheck()); for arg in self.hir(file).ids(args) { - self.type_of_expr(file, arg); + let ty = self.type_of_expr(file, arg); + // `checkSpreadExpression` + if let ExprKind::Spread(operand) = self.hir(file)[arg].kind { + self.check_iterated_type_of_spread_element(file, ty, operand); + } } if let Some(outer) = outer { self.end_recheck(outer); @@ -882,7 +916,7 @@ impl<'p, 's> Checker<'p, 's> { } } - /// `resolveInstanceofExpression`. 2359 is reported elsewhere. + /// `resolveInstanceofExpression` fn resolve_instanceof_expression( &mut self, file: FileId, @@ -900,15 +934,28 @@ impl<'p, 's> Checker<'p, 's> { if self.is_any(right_type) { return any_signature; } + // `resolveErrorCall` + let unknown_signature = ResolvedCall { + sig: None, + ret: TypeId::ERROR, + }; let Some(method) = self.symbol_has_instance_method_of_object_type(right_type) else { - return any_signature; + let function = self.global_ref(known::Function, &[]); + if !self.signatures(right_type, false).is_empty() + || !self.signatures(right_type, true).is_empty() + || self.is_subtype(right_type, function) + { + return any_signature; + } + let since = self.reported.len(); + self.error(file, self.hir(file).child(right), 2359, &[]); + let reported = self.take_reported_from(since); + (self.call_resolution_errors.get_or_insert_default()).extend(reported); + return unknown_signature; }; let apparent = self.apparent_type(method); if self.is_error_type(apparent) { - return ResolvedCall { - sig: None, - ret: TypeId::ERROR, - }; + return unknown_signature; } let sigs = self.signatures(apparent, false); let constructs = self.signatures(apparent, true).len(); @@ -1117,7 +1164,11 @@ impl<'p, 's> Checker<'p, 's> { self.resolved_meanwhile.pop(); // Another checker may be the one to report it. let reported = self.take_reported_from(since); - if !reported.is_empty() { + // Where `addDiagnostic` has discarded them, the entry says that + // `getCandidateForOverloadFailure` has deferred the call. + if !reported.is_empty() + || self.serialization_level >= super::sink::MAX_SERIALIZATION_LEVEL + { (self.call_resolution_errors.get_or_insert_default()).extend(reported); } } @@ -1272,9 +1323,12 @@ impl<'p, 's> Checker<'p, 's> { let inference_target_type = self.return_type_in_chain(file, call, signature); if self.could_contain_type_variables(inference_target_type) { let outer_context = self.get_inference_context(file, call); - let is_from_binding_pattern = !skip_binding_patterns - && self.contextual_type(file, call, ContextFlags::SKIP_BINDING_PATTERNS) - != Some(contextual_type); + let is_from_binding_pattern = !skip_binding_patterns && { + self.requested_assignment_target = None; + self.contextual_type(file, call, ContextFlags::SKIP_BINDING_PATTERNS) + != Some(contextual_type) + || self.is_contextual_type_created_anew(contextual_type) + }; if !is_from_binding_pattern { // `getMapperFromContext(cloneInferenceContext(outerContext, InferenceFlagsNoDefault))` let instantiated_type = outer_context @@ -1304,7 +1358,6 @@ impl<'p, 's> Checker<'p, 's> { let mut return_context = Inference::for_params(&context.params, Some(signature)); return_context.any_default = context.any_default; - return_context.from_pattern = is_from_binding_pattern; let return_source_type = match outer_context { Some(level) => { self.instantiate_with_outer_return_mapper(level, contextual_type) @@ -1317,14 +1370,6 @@ impl<'p, 's> Checker<'p, 's> { inference_target_type, 0, ); - // `nonInferrableAnyType`: the names in a pattern can have any type, and nothing - // is inferred from that. - if is_from_binding_pattern { - for c in &mut return_context.candidates { - c.covariant.retain(|t| !self.has_any_flag(*t)); - c.contravariant.retain(|t| !self.has_any_flag(*t)); - } - } context.return_context = Self::clone_inferred_part_of_context(&return_context); } } @@ -1371,6 +1416,115 @@ impl<'p, 's> Checker<'p, 's> { self.inference_mapper(context) } + /// Whether the call of `getContextualType` that has just returned `contextual_type` created it, + /// so that it is identical to the result of no other call. The contextual type of an assigned + /// value is `getTypeOfExpression(left)`: `checkObjectLiteral` creates a type on every call, and + /// `flowTypeCache` keeps it only if the check needed control flow analysis. + fn is_contextual_type_created_anew(&mut self, contextual_type: TypeId) -> bool { + let Some((file, left)) = self.requested_assignment_target.take() else { + return false; + }; + self.contains_type_of_literal_in(contextual_type, file, left) + && self.is_checked_without_flow_analysis(file, left) + } + + /// Whether `ty` is the type of an object literal inside `within`, or is composed of one. + fn contains_type_of_literal_in(&mut self, ty: TypeId, file: FileId, within: ExprId) -> bool { + let object_flags = self.types().object_flags(ty); + if !object_flags.contains(ObjectFlags::CONTAINS_OBJECT_OR_ARRAY_LITERAL) { + return false; + } + let (of, literal) = match self.data(ty) { + TypeData::Anon { + origin: Origin::ObjectLiteral(of, literal, ..), + .. + } => (*of, *literal), + TypeData::Synth(shape) => match shape.symbol_declared_at { + Some((of, _, literal)) if literal.is_some() => (of, literal), + _ => return false, + }, + TypeData::Union(parts) | TypeData::Intersection(parts) => { + return (parts.iter()) + .any(|&part| self.contains_type_of_literal_in(part, file, within)); + } + TypeData::Ref { .. } | TypeData::Tuple { .. } => { + return (self.type_arguments(ty).iter()) + .any(|&part| self.contains_type_of_literal_in(part, file, within)); + } + _ => return false, + }; + let hir = self.hir(file); + of == file && hir[within].pos <= hir[literal].pos && hir[literal].end <= hir[within].end + } + + /// Whether `checkExpression(e)` leaves `flowInvocationCount` as it is, whatever has been + /// resolved by then. `false`: that is not known. + fn is_checked_without_flow_analysis(&self, file: FileId, e: ExprId) -> bool { + if e.is_none() { + return false; + } + let (hir, bound) = (self.hir(file), self.bound(file)); + match hir[e].kind { + ExprKind::Missing + | ExprKind::Null + | ExprKind::True + | ExprKind::False + | ExprKind::Number(_) + | ExprKind::String(_) + | ExprKind::BigInt(_) + | ExprKind::Regex => true, + ExprKind::Template { exprs } => exprs.is_empty(), + // `checkIdentifier` returns the declared type of a variable that is assigned. A + // declaration that precedes has been checked, so that type is resolved. + ExprKind::Ident(_) => { + let symbol = bound.expr_symbol[e.idx()]; + symbol.is_some() && self.target_kind(file, e).definite && { + let declarations = &bound.symbols[symbol.idx()].decls; + !declarations.is_empty() + && declarations.iter().all(|&declaration| { + matches!(declaration, Decl::Var(name) | Decl::Param(name) + if hir[name].pos < hir[e].pos) + }) + } + } + ExprKind::Spread(operand) | ExprKind::NonNull(operand) => { + self.is_checked_without_flow_analysis(file, operand) + } + ExprKind::Assign { + op: None, + target, + value, + } => { + self.is_checked_without_flow_analysis(file, target) + && self.is_checked_without_flow_analysis(file, value) + } + ExprKind::Array(elements) => (hir.ids(elements)) + .all(|element| self.is_checked_without_flow_analysis(file, element)), + ExprKind::Object(props) => props.iter().all(|p| { + let prop = &hir[p]; + if prop.value.is_none() { + return false; + } + if let PropKey::Computed(key) = prop.key + && !self.is_checked_without_flow_analysis(file, key) + { + return false; + } + match (prop.kind, hir[prop.value].kind) { + // `checkObjectLiteral`: not the default, in a destructuring pattern. + (PropKind::Shorthand, ExprKind::Assign { target, .. }) => { + self.is_checked_without_flow_analysis(file, target) + } + (PropKind::Init | PropKind::Shorthand | PropKind::Spread, _) => { + self.is_checked_without_flow_analysis(file, prop.value) + } + _ => false, + } + }), + _ => false, + } + } + /// `checkExpressionWithContextualType` for an argument. pub(super) fn check_argument( &mut self, @@ -1400,7 +1554,10 @@ impl<'p, 's> Checker<'p, 's> { (ty, node) } // `checkSpreadExpression` - Arg::SpreadElement(ty, _, _, node) => (ty, node), + Arg::SpreadElement(_, list, operand, node) => ( + self.check_iterated_type_of_spread_element(file, list, operand), + node, + ), }; // FOR SPEED: `instantiateTypeWithSingleGenericCallSignature` returns `ty`, which is not a // fresh literal type. @@ -1426,7 +1583,7 @@ impl<'p, 's> Checker<'p, 's> { } /// `getSignatureInstantiationWithoutFillingInTypeArguments(signature, signature.typeParameters)` - fn without_filling_in_type_arguments(&mut self, generic: SigId) -> SigId { + pub(super) fn without_filling_in_type_arguments(&mut self, generic: SigId) -> SigId { let (params, ret, this) = ( self.sig_params(generic), self.sig_return(generic), @@ -1437,7 +1594,7 @@ impl<'p, 's> Checker<'p, 's> { params: self.list(¶ms), ret, this, - of: ArenaBox::empty(), + of: self.list(&[generic]), is_union: true, }) } @@ -1529,15 +1686,7 @@ impl<'p, 's> Checker<'p, 's> { }); let returned_type = self.sig_return(sig); let ret = self.single_signature_type(generalized, construct, returned_type, mapper); - let (params, this) = (self.sig_params(sig), self.sig_this_type(sig)); - self.types().intern_sig(SigData::Synth { - type_params: ArenaBox::empty(), - params: self.list(¶ms), - ret, - this, - of: ArenaBox::empty(), - is_union: true, - }) + self.types().intern_sig(SigData::WithReturn { sig, ret }) } /// `addImplementationSuccessElaboration`: the implementation of the overload `failed`, if @@ -1696,7 +1845,10 @@ impl<'p, 's> Checker<'p, 's> { /// `createUnionOfSignaturesForOverloadFailure`: it accepts what any of `sigs` accepts, and /// returns what all of them return. pub(super) fn union_of_signatures_for_overload_failure(&mut self, sigs: &[SigId]) -> SigId { - let lists: Vec> = sigs.iter().map(|&sig| self.sig_params(sig)).collect(); + // `tryGetTypeAtPosition` for every position, and `tryGetRestTypeOfSignature`. + let lists: Vec> = (sigs.iter()) + .map(|&sig| self.sig_params_up_to(sig, usize::MAX)) + .collect(); // `getNonRestParameterCount` let plain = |list: &[SigParam]| list.len() - usize::from(list.last().is_some_and(|p| p.rest)); @@ -1820,21 +1972,38 @@ impl<'p, 's> Checker<'p, 's> { return Some((file, start, self.end_of_type_args(file, nodes))); } // An empty list begins and ends after the `<`, which follows the expression. - let expression = match node { + let after = + |expression| skip_trivia(&hir.text, self.end_of_expr(file, expression) as usize); + let less_than = match node { InstantiationExpression::Expr(_, e) => match hir[e].kind { - ExprKind::Instantiation { expr, .. } => expr, + ExprKind::Instantiation { expr, .. } => after(expr), _ => return None, }, InstantiationExpression::TypeNode(_, node) => match hir[node].kind { - TypeNodeKind::Typeof { expr, .. } => expr, + TypeNodeKind::Typeof { expr, .. } => after(expr), + TypeNodeKind::Import { .. } => { + self.empty_type_argument_list_of_import_type(file, node)? as usize + } _ => return None, }, }; - let less_than = skip_trivia(&hir.text, self.end_of_expr(file, expression) as usize); let start = skip_trivia(&hir.text, less_than + 1) as u32; Some((file, start, super::explain::NO_LENGTH)) } + /// `node.TypeArgumentList() != nil && len(node.TypeArguments()) == 0` for the `ImportType` + /// `node`, which then ends with `<>`: the position of the `<`. `TypeNodeKind::Import` is as + /// large as a `TypeNodeKind` may be, so it has no `has_type_arguments` as `Typeof` has. + pub(super) fn empty_type_argument_list_of_import_type( + &self, + file: FileId, + node: TypeNodeId, + ) -> Option { + let hir = self.hir(file); + let greater_than = start_of_token_before(&hir.text, hir[node].end, b">")?; + start_of_token_before(&hir.text, greater_than, b"<") + } + /// `node.TypeArgumentList()` fn type_argument_nodes(&self, node: InstantiationExpression) -> (FileId, IdList) { match node { @@ -2216,6 +2385,18 @@ impl<'p, 's> Checker<'p, 's> { self.normalized_tuple(&[t], &[ElemFlags::VARIADIC], false) } + /// `checkIteratedTypeOrElementType(IterationUseSpread, spreadType, c.undefinedType, + /// arg.Expression())` for a `SpreadElement` with that operand. + fn check_iterated_type_of_spread_element( + &mut self, + file: FileId, + spread_type: TypeId, + operand: ExprId, + ) -> TypeId { + let error_node = self.span_of_parenthesized_expr(file, operand); + self.check_iterated_type_of_spread(spread_type, error_node) + } + /// `getSpreadArgumentType` pub(super) fn spread_argument_type( &mut self, @@ -2247,7 +2428,12 @@ impl<'p, 's> Checker<'p, 's> { if self.is_array_like(spread_type) { return self.mutable_array_or_tuple(spread_type); } - let element = self.iterated_type_of_spread(spread_type); + let element = match args.last() { + Some(&Arg::SpreadElement(_, _, operand, _)) => { + self.check_iterated_type_of_spread_element(file, spread_type, operand) + } + _ => self.iterated_type_of_spread(spread_type), + }; return if is_const { self.readonly_array_of(element) } else { @@ -2260,13 +2446,16 @@ impl<'p, 's> Checker<'p, 's> { let mut flags: SmallVec<[ElemFlags; 8]> = SmallVec::with_capacity(length); for i in index..args.len() { let (ty, flag) = match args[i] { - Arg::Spread(element, list, ..) | Arg::SpreadElement(element, list, ..) => { - if self.is_array_like(list) { - (list, ElemFlags::VARIADIC) - } else { - (element, ElemFlags::REST) - } + Arg::Spread(_, list, ..) | Arg::SpreadElement(_, list, ..) + if self.is_array_like(list) => + { + (list, ElemFlags::VARIADIC) } + Arg::Spread(element, ..) => (element, ElemFlags::REST), + Arg::SpreadElement(_, list, operand, _) => ( + self.check_iterated_type_of_spread_element(file, list, operand), + ElemFlags::REST, + ), arg => { let contextual = if self.is_tuple(rest) { self.contextual_element_at(rest, i - index, Some(length), None, None) @@ -2680,7 +2869,7 @@ impl<'p, 's> Checker<'p, 's> { /// The name that the mapper `around` of a clone gives the type parameter declared as /// `declared`: see `unique_type_params`. - fn new_type_param_name(&self, declared: Atom, around: MapperId) -> Option { + pub(super) fn new_type_param_name(&self, declared: Atom, around: MapperId) -> Option { if around == MapperId::IDENTITY { return None; } @@ -2724,9 +2913,9 @@ impl<'p, 's> Checker<'p, 's> { /// `getUniqueTypeParameters`: `own`, with a renamed clone for each type parameter whose name occurs in `inferred` or earlier in /// `own`. The mapper of a renamed clone (`cloneTypeParameter`) maps the fresh string literal type of the declared name to the string /// literal type of the new name. Instantiation only looks up type parameters, so that entry never reaches a type. - /// `clone_mapper` resolves the siblings of a clone with the mapper of the clone, so if a type parameter is renamed, its siblings - /// (those of the same function, class or interface with the same mapper) are cloned with the same mapper, and those that keep - /// their name only change identity. + /// A type parameter that keeps its declared name stays as it is: its constraint and its default name the old siblings. + /// `clone_mapper` resolves the renamed siblings of a clone (those of the same function, class or interface with the same mapper) + /// with the mapper of the clone, so one that an earlier call renamed is cloned again with the same mapper. /// `None`: the renamed clones cannot be represented. pub(super) fn unique_type_params( &self, @@ -2803,7 +2992,9 @@ impl<'p, 's> Checker<'p, 's> { .filter(|rename| sibling_sets[rename.0] == sibling_sets[i]) .map(|rename| (rename.1, rename.2)) .collect(); - if renames_of_siblings.is_empty() { + let has_new_name = + renames.iter().any(|rename| rename.0 == i) || self.is_renamed_type_param(param); + if renames_of_siblings.is_empty() || !has_new_name { unique.push(param); continue; } diff --git a/src/sema/check/check_source_file.rs b/src/sema/check/check_source_file.rs index 3a83e0e52c03..06042ff91713 100644 --- a/src/sema/check/check_source_file.rs +++ b/src/sema/check/check_source_file.rs @@ -11,6 +11,7 @@ use super::errors_operators::{ check_tagged_template, check_template_spans, check_yield_result, }; use super::errors_statements::is_with_statement; +use super::sink::MAX_SERIALIZATION_LEVEL; use super::task::{Finished, Published}; use super::*; use crate::bind::{Decl, FnOwner, Parent, PatParent}; @@ -170,16 +171,22 @@ impl<'s> Checker<'_, 's> { self.renamed_binding_elements_in_types.clear(); self.unvisited_exprs.clear(); let hir = self.hir(file); - let is_ambient = |flags: Flags| flags.contains(Flags::AMBIENT); + // `parseDeclaration`, `parseClassElement`: outside a declaration file only a `declare` + // sets `NodeFlagsAmbient`. + let mut modifiers = hir.modifiers.iter(); self.has_ambient_context = hir.kind == FileKind::Declaration - || hir.modules.iter().any(|it| is_ambient(it.flags)) - || hir.classes.iter().any(|it| is_ambient(it.flags)) - || hir.fns.iter().any(|it| is_ambient(it.flags)); + || modifiers.any(|modifier| modifier.kind.flag() == Flags::AMBIENT); self.parsed_again_for_await = None; // The kinds that `type_of_expr_uncached` defers. Sorted by position: a single evaluation // reaches them in that order. let index = self.exprs_by_kind(file); - let tags = [ExprTag::Fn, ExprTag::Class, ExprTag::Jsx, ExprTag::Unary]; + let tags = [ + ExprTag::Fn, + ExprTag::Class, + ExprTag::Jsx, + ExprTag::Unary, + ExprTag::As, + ]; let mut earlier: Vec = (tags.iter()) .flat_map(|&tag| index.of(tag).iter().copied()) .filter(|&e| (self.p.deferred_nodes.get(&self.task, &(file, e))).is_some()) @@ -190,8 +197,7 @@ impl<'s> Checker<'_, 's> { } self.check_source_elements(file, self.hir(file).body); self.check_deferred_nodes(file); - // `checkFunctionOrConstructorSymbol`, which compares an implementation with its overloads. - self.check_overloads(file); + self.check_merged_symbols(file); self.check_exprs_visited_by_queries(file); if hir.kind != FileKind::Declaration { self.check_unused_renamed_binding_elements(file); @@ -207,6 +213,9 @@ impl<'s> Checker<'_, 's> { fn check_exprs_visited_by_queries(&mut self, file: FileId) { let mut unvisited = Vec::new(); loop { + // `onFailedToResolveSymbol` is part of the walk: `getSpellingSuggestionForName` resolves + // the aliases among its candidates, and `getTargetOfAliasLikeExpression` checks. + self.report_unresolved_identifiers(); unvisited.append(&mut self.unvisited_exprs); let (visited, rest): (Vec<_>, Vec<_>) = unvisited.into_iter().partition(|&(_, e)| { self.cached_type_of_expr(file, e).is_some() @@ -226,6 +235,7 @@ impl<'s> Checker<'_, 's> { self.never_check_unless_visited_by_query(file, self.hir(file).node(e), range); } self.never_check_with_bodies(file); + self.never_check_specifier_expressions(file); } /// Whether `pos` is in a range given to `never_check`. @@ -362,7 +372,7 @@ impl<'s> Checker<'_, 's> { /// `checkSourceElement`: `c.currentNode = node`, `c.instantiationCount = 0`. Returns /// `saveCurrentNode`. #[inline] - fn enter_source_element(&mut self, node: CurrentNode) -> Option { + pub(super) fn enter_source_element(&mut self, node: CurrentNode) -> Option { self.instantiation_count = 0; self.current_source_element.replace(node) } @@ -388,7 +398,7 @@ impl<'s> Checker<'_, 's> { } } self.check_getter_returns_a_value(file, func); - if hir[func].ret.is_none() { + if hir[func].ret.is_none() && hir[func].kind != FnKind::Setter { self.return_type_of_fn(file, func); } self.check_all_code_paths_in_non_void_function_return_or_throw(file, func); @@ -445,6 +455,10 @@ impl<'s> Checker<'_, 's> { /// `checkSourceElement(node.Body())`, `checkExpressionCached(node.Body())` fn check_function_body(&mut self, file: FileId, func: FnId) { let function = &self.hir(file)[func]; + // `checkBlock` + if matches!(function.body, FnBody::Block(_)) { + self.check_grammar_function_body_in_ambient_context(file, func); + } match function.body { // A static block is not function-like. FnBody::Block(list) if function.kind == FnKind::StaticBlock => { @@ -478,9 +492,9 @@ impl<'s> Checker<'_, 's> { } } - /// `checkTypeParameters`: 2706. + /// `checkTypeParameters`: 2300 2706. fn check_type_parameters(&mut self, file: FileId, type_params: Span) { - let hir = self.hir(file); + let (hir, symbols) = (self.hir(file), &self.bound(file).type_param_symbol); let mut seen_default = false; for (index, tp) in type_params.iter().enumerate() { self.check_type_parameter(file, tp); @@ -496,6 +510,11 @@ impl<'s> Checker<'_, 's> { let at = (file, hir[tp].start, self.end_of_type_param(file, tp)); self.error_at(at, 2706, &[]); } + let symbol = symbols[tp.idx()]; + let mut earlier = type_params.iter().take(index); + if symbol.is_some() && earlier.any(|it| symbols[it.idx()] == symbol) { + self.report_on_declaration_name(file, Decl::TypeParam(tp), 2300); + } } } @@ -697,6 +716,7 @@ impl<'s> Checker<'_, 's> { } let hir = self.hir(file); self.check_signature_declaration(file, func); + self.check_function_or_constructor_symbols_of(file, Decl::Fn(func)); self.check_function_body(file, func); self.check_all_code_paths_in_non_void_function_return_or_throw(file, func); if hir[func].ret.is_none() @@ -722,7 +742,7 @@ impl<'s> Checker<'_, 's> { if !exits || !matches!(self.hir(file)[name].kind, PatKind::Ident(_)) { self.check_binding_name(file, name, is_bodiless); } - if exits { + if exits || self.is_binding_pattern_in_ambient_or_type_node(file, name) { self.leave_unvisited(file, initializer); } else { self.check_expression(file, initializer); @@ -730,6 +750,19 @@ impl<'s> Checker<'_, 's> { exits } + /// `IsBindingPattern(name) && isInAmbientOrTypeNode(node)`, for the declaration `node` of + /// `name`: `checkVariableLikeDeclaration` returns before it validates the initializer. + pub(super) fn is_binding_pattern_in_ambient_or_type_node( + &self, + file: FileId, + name: PatId, + ) -> bool { + let hir = self.hir(file); + name.is_some() + && matches!(hir[name].kind, PatKind::Object(_) | PatKind::Array(_)) + && hir.is_in_ambient_or_type_node(hir.node(name)) + } + /// The check of the parent of `e` returns before it checks `e`. pub(super) fn leave_unvisited(&mut self, file: FileId, e: ExprId) { if e.is_some() { @@ -880,17 +913,19 @@ impl<'s> Checker<'_, 's> { } let start = hir[hir[p].value].pos; let (node, name) = match hir[hir[p].value].kind { - PatKind::Ident(name) if name != known::empty => { - (self.place_of_token(file, start), Arg::Atom(name)) - } - _ => ((file, start, start), Arg::Bytes(b"(Missing)")), + PatKind::Ident(name) if name != known::empty => ( + self.place_of_token(file, start), + self.declaration_name_at(file, start), + ), + _ => ((file, start, start), b"(Missing)".to_vec()), }; let property = self.declaration_name_at(file, hir[p].key_pos); let related = hir[param].ty.is_none().then(|| { let end = self.end_of_param(file, param); self.new_diagnostic((file, end, end), 2843, &[Arg::Bytes(&property)]) }); - let diagnostic = self.error_at(node, 2842, &[name, Arg::Bytes(&property)]); + let args = [Arg::Bytes(&name), Arg::Bytes(&property)]; + let diagnostic = self.error_at(node, 2842, &args); if let Some(related) = related { diagnostic.add_related_info(related); } @@ -949,7 +984,11 @@ impl<'s> Checker<'_, 's> { self.leave_unvisited(file, decl.init); return; } - self.check_expression(file, decl.init); + if self.is_binding_pattern_in_ambient_or_type_node(file, decl.pat) { + self.leave_unvisited(file, decl.init); + } else { + self.check_expression(file, decl.init); + } self.check_variable_initializer(file, d); if matches!(decl.kind, VarKind::Using | VarKind::AwaitUsing) { self.check_initializer_of_using_declaration(file, d); @@ -984,8 +1023,14 @@ impl<'s> Checker<'_, 's> { self.check_expression(file, decl.extends); self.check_type_arguments_of_base(file, class, sym); self.report_class_like_declaration(file, class, sym); + } else { + self.check_heritage_clause_elements(file, decl.implements); } - self.check_heritage_clause_elements(file, decl.implements); + for other in self.hir(file).ids(decl.other_extends) { + self.leave_unvisited(file, other); + } + self.leave_heritage_expressions_unvisited(file, decl.implements); + self.leave_heritage_expressions_unvisited(file, decl.other_implements); if symbol.is_some() { self.check_class_heritage(file, class); self.check_property_initialization(file, class); @@ -1018,9 +1063,16 @@ impl<'s> Checker<'_, 's> { } if symbol.is_some() { self.check_interface_heritage(file, interface); + // `getMembersOfSymbol`: `checkInheritedPropertiesAreIdentical` or + // `checkIndexConstraints` has asked for the members. + self.late_bound_members(self.files().sym(file, symbol), false); } + let node = self.hir(file).node(interface); + self.check_object_type_for_duplicate_declarations(file, node, decl.members, false); self.check_bases_of_interface(file, interface); self.check_heritage_clause_elements(file, decl.extends); + self.leave_heritage_expressions_unvisited(file, decl.extends); + self.leave_heritage_expressions_unvisited(file, decl.other_heritage); self.check_members(file, decl.members); } @@ -1100,10 +1152,15 @@ impl<'s> Checker<'_, 's> { self.check_grammar_constructor_type_annotation(file, member.func); } // `checkComputedPropertyName` - if let PropKey::Computed(key) = member.key - && !self.is_computed_name_never_checked(file, key) - { - self.check_expression(file, key); + if let PropKey::Computed(key) = member.key { + if self.is_computed_name_never_checked(file, key) { + self.leave_unvisited(file, key); + } else { + self.check_expression(file, key); + } + } + if member.kind == MemberKind::Method { + self.check_function_or_constructor_symbols_of(file, Decl::Member(m)); } // `checkAccessorDeclaration`: `getTypeOfAccessors` comes before the body, whose `return` // asks for the return type of the signature, which is another resolution. @@ -1118,13 +1175,14 @@ impl<'s> Checker<'_, 's> { self.check_all_code_paths_in_non_void_function_return_or_throw(file, member.func); } if member.kind == MemberKind::Constructor { + self.check_function_or_constructor_symbols_of(file, Decl::Member(m)); self.check_super_call_in_constructor(file, m); } // `checkVariableLikeDeclaration`: `getTypeOfSymbol` comes before // `checkExpressionCached(initializer)`, unless the name is computed. if member.kind == MemberKind::Property && !matches!(member.key, PropKey::Computed(_)) - && member.ty.is_none() + && !is_resolved_by_check_source_element(hir, member.ty) && self.bound(file).member_symbol[m.idx()].is_some() { let symbol = self.symbol_of_member(file, m); @@ -1159,7 +1217,7 @@ impl<'s> Checker<'_, 's> { /// The first test of `checkComputedPropertyName`: `e` is `a in b`, and `[e]` is the name of a /// member of a type literal, a class or an interface that is no accessor. Its type is the error /// type, and it is not checked. - fn is_computed_name_never_checked(&self, file: FileId, e: ExprId) -> bool { + pub(super) fn is_computed_name_never_checked(&self, file: FileId, e: ExprId) -> bool { let hir = self.hir(file); matches!(hir[e].kind, ExprKind::Binary { op: BinOp::In, .. }) && !is_parenthesized(hir, e) @@ -1259,6 +1317,20 @@ impl<'s> Checker<'_, 's> { } } + /// `checkTypeReferenceNode` never visits the expression of an element that is no entity name. + /// The keyword `import`, a missing expression, has nothing below it. + fn leave_heritage_expressions_unvisited(&mut self, file: FileId, elements: IdList) { + let hir = self.hir(file); + for element in hir.ids(elements) { + if element.is_some() + && let TypeNodeKind::Heritage { expr, .. } = hir[element].kind + && !matches!(hir[expr].kind, ExprKind::Missing) + { + self.leave_unvisited(file, expr); + } + } + } + /// `checkSourceElement` for a type node. pub(super) fn check_type_node(&mut self, file: FileId, node: TypeNodeId) { if node.is_none() || self.is_stack_low() { @@ -1270,7 +1342,7 @@ impl<'s> Checker<'_, 's> { } /// `checkSourceElementWorker` for a type node. - fn check_type_node_worker(&mut self, file: FileId, node: TypeNodeId) { + pub(super) fn check_type_node_worker(&mut self, file: FileId, node: TypeNodeId) { let hir = self.hir(file); match hir[node].kind { // `checkTypeReferenceNode` @@ -1278,6 +1350,8 @@ impl<'s> Checker<'_, 's> { self.check_type_nodes(file, args); self.check_type_reference_or_import(file, node); } + // `checkTypeReferenceNode`: `getTypeReferenceName` is nil, so it has the error type. + TypeNodeKind::Heritage { args, .. } => self.check_type_nodes(file, args), // `checkImportType` checks the argument, never the type arguments. A non-literal argument is stored in `args` (`spec` is `NONE`). TypeNodeKind::Import { spec, args, .. } => { if spec.is_none() { @@ -1292,8 +1366,8 @@ impl<'s> Checker<'_, 's> { // `checkTypeQuery`: `checkExpressionWithTypeArguments` TypeNodeKind::Typeof { args, expr, .. } => { self.check_type_nodes(file, args); - self.check_expression(file, expr); self.type_from_node(file, node); + self.check_expression(file, expr); } // `checkTypeLiteral` TypeNodeKind::Object(members) => { @@ -1302,6 +1376,10 @@ impl<'s> Checker<'_, 's> { if (members.iter()).any(|m| hir[m].kind == MemberKind::IndexSignature) { self.check_index_constraints(file, ty, &[(file, members)], false, None); } + // Another task may have stored `ty`. + self.get_members_of_type_literal(file, members); + let literal = hir.node(node); + self.check_object_type_for_duplicate_declarations(file, literal, members, false); } // `checkArrayType`, `checkTypeOperator` TypeNodeKind::Array(of) | TypeNodeKind::Keyof(of) => self.check_type_node(file, of), @@ -1484,7 +1562,7 @@ impl<'s> Checker<'_, 's> { if matches!(hir[s].kind, StmtKind::ExportAssign(_)) { self.check_grammar_export_equals(file, s); } - } else if e.is_some() && matches!(bound.stmt_parent[s.idx()], Parent::Module(_)) { + } else if e.is_some() { self.never_check(self.start_of(file, e), hir[s].loc.end); } if matches!(hir[s].kind, StmtKind::ExportAssign(_)) @@ -1495,15 +1573,22 @@ impl<'s> Checker<'_, 's> { self.error(file, s, 1294, &[]); } } - // `checkImportBinding` of `* as ns`: `checkAliasSymbol` begins with `resolveAlias`. The - // first use of a module decides whether it has a synthetic `default`. - StmtKind::Import(x) if hir[x].namespace.is_some() => { + // `checkImportBinding` of the default name, of `* as ns` and of each name in braces: + // `checkAliasSymbol` begins with `resolveAlias`. What a later statement asks of the alias + // finds it resolved, or being resolved. The first use of a module decides whether it has + // a synthetic `default`. + StmtKind::Import(x) => { let scope = bound.import_scope[x.idx()]; - if scope.is_some() - && let Some(local) = - bound.lookup(bound.scopes[scope.idx()].locals, hir[x].namespace) - { - self.resolve_alias(self.files().sym(file, local)); + if scope.is_some() { + let locals = bound.scopes[scope.idx()].locals; + let named = hir[x].named.iter().map(|item| hir[item].local); + for name in [hir[x].default, hir[x].namespace].into_iter().chain(named) { + if name.is_some() + && let Some(local) = bound.lookup(locals, name) + { + self.resolve_alias(self.files().sym(file, local)); + } + } } } // `checkGrammarTypeOnlyNamedImportsOrExports`: `type` on the statement and again on a @@ -1755,6 +1840,9 @@ impl<'s> Checker<'_, 's> { } let hir = self.hir(file); let ty = self.type_of_expr(file, e); + if ty == TypeId::ERROR { + self.reach_flow_depth_limit_again(file, e); + } // `checkExpressionEx` let ty = match hir[e].kind { ExprKind::Spread(_) => self.type_of_spread_expression(file, e, ty), @@ -1775,6 +1863,11 @@ impl<'s> Checker<'_, 's> { } // `resolveCall`: the type arguments of `super()` are those of the `extends` clause. ExprKind::Call(c) | ExprKind::New(c) | ExprKind::TaggedTemplate(c) => { + let serialization_level = self.serialization_level; + if self.task.file == Some(file) && self.signatures_resolved_discarding.contains(&e) + { + self.serialization_level = serialization_level.max(MAX_SERIALIZATION_LEVEL); + } let callee = hir[c].callee; self.check_expression(file, callee); if callee.is_none() || !matches!(hir[callee].kind, ExprKind::Super) { @@ -1786,11 +1879,16 @@ impl<'s> Checker<'_, 's> { .is_some() { self.check_node_deferred(file, e); + } else if ty == TypeId::SILENT_NEVER && self.is_silent_never_signature(file, e) { + for x in hir.ids(hir[c].args) { + self.leave_unvisited(file, x); + } } else { for x in hir.ids(hir[c].args) { self.check_expression(file, x); } } + self.serialization_level = serialization_level; if matches!(hir[e].kind, ExprKind::TaggedTemplate(_)) { check_tagged_template(self, file, c); } @@ -1812,8 +1910,9 @@ impl<'s> Checker<'_, 's> { self.check_expression(file, expr); } } - // `checkFunctionExpressionOrObjectLiteralMethod`: the signature now, and its return - // type if it is contextually typed. + // `checkFunctionExpressionOrObjectLiteralMethod`: `type_of_expr` has run + // `contextuallyCheckFunctionExpressionOrObjectLiteralMethod`, with the contextual + // signature there was at the first look. ExprKind::Fn(func) => { if hir[func].kind == FnKind::Expr { self.check_collisions_for_declaration_name(file, e, hir[func].name); @@ -1827,9 +1926,6 @@ impl<'s> Checker<'_, 's> { self.check_grammar_for_generator(file, func); } self.check_signature_declaration(file, func); - if hir[func].ret.is_none() && self.contextual_signature(file, func).is_some() { - self.return_type_of_fn(file, func); - } self.check_node_deferred(file, e); } // `checkClassExpression`: `type_of_expr` has run `checkClassLikeDeclaration`. @@ -1903,10 +1999,12 @@ impl<'s> Checker<'_, 's> { { self.check_expression(file, value); self.check_destructuring_assignment_target(file, target); - // One that is a default in a pattern is checked with the pattern. - if !self.is_definite_assignment_target(file, e) { + if !self.is_assignment_element_with_initializer(file, e) { let source_type = self.type_of_expr(file, value); + // `checkExpressionEx`: `c.currentNode = node` + let saved = self.enter_source_element(CurrentNode::Expr(file, e)); self.check_destructuring_assignment(file, target, source_type); + self.current_source_element = saved; } } // `checkBinaryLikeExpression`. It iterates over the left spine, as TypeScript's trampoline does, so that a long chain @@ -1948,16 +2046,19 @@ impl<'s> Checker<'_, 's> { } } } - ExprKind::Index { - obj: a, index: b, .. + ExprKind::Index { obj, index, .. } => { + self.check_expression(file, obj); + self.check_expression(file, index); } - | ExprKind::Assign { - target: a, - value: b, - .. - } => { - self.check_expression(file, a); - self.check_expression(file, b); + // `checkBinaryLikeExpression`: `checkAssignmentOperator`. `type_of_expr` has that of a + // compound assignment. + ExprKind::Assign { target, value, .. } => { + self.check_expression(file, target); + self.check_expression(file, value); + // `checkExpressionEx`: `c.currentNode = node` + let saved = self.enter_source_element(CurrentNode::Expr(file, e)); + self.check_plain_assignment_operator(file, e, None); + self.current_source_element = saved; } ExprKind::Cond { test, yes, no } => { self.check_expression(file, test); @@ -1978,6 +2079,18 @@ impl<'s> Checker<'_, 's> { } } + /// `getTypeAtFlowNode`, `c.flowAnalysisDisabled = true`, for a reference `e` whose stored type + /// is `errorType`. No type of a reference is stored there: one that a query has checked before, + /// and whose walk reached the depth limit, reaches it again. + #[cold] + fn reach_flow_depth_limit_again(&mut self, file: FileId, e: ExprId) { + if self.bound(file).flow_places > super::flow::MAX_FLOW_DEPTH + && (self.p.flows_too_deep.get(&self.task, &(file, e))).is_some() + { + self.flow_analysis_disabled = true; + } + } + /// Whether `e` is the name of `{ e = 1 }` outside a destructuring pattern, where /// `checkShorthandPropertyAssignment` checks the `ObjectAssignmentInitializer` in its place: /// nothing resolves the name. @@ -2007,16 +2120,18 @@ impl<'s> Checker<'_, 's> { match hir[e].kind { ExprKind::Object(properties) if !is_parenthesized(hir, e) => { for (i, p) in properties.iter().enumerate() { - if let PropKey::Computed(key) = hir[p].key { - self.check_expression(file, key); - } // A rest element that is not last is rejected and not visited. Neither is a - // member that is not a property assignment. + // member that is not a property assignment, nor its name. let continues = match hir[p].kind { PropKind::Init | PropKind::Shorthand => true, PropKind::Spread => i + 1 == properties.len(), _ => false, }; + match hir[p].key { + PropKey::Computed(key) if continues => self.check_expression(file, key), + PropKey::Computed(key) => self.leave_unvisited(file, key), + _ => {} + } if continues { self.check_destructuring_assignment_target(file, hir[p].value); } @@ -2073,3 +2188,20 @@ impl<'s> Checker<'_, 's> { } } } + +/// FOR SPEED: whether `checkSourceElement(node)` leaves nothing for `getTypeFromTypeNode(node)` to +/// resolve, so that `getTypeOfSymbol` of the property that `node` annotates cannot close a cycle. +/// `checkTypeOperator`, `checkConditionalType`, `checkArrayType` and `checkJSDocType` visit the +/// children and do not ask for the type of `node`. +fn is_resolved_by_check_source_element(hir: &File, node: TypeNodeId) -> bool { + node.is_some() + && match hir[node].kind { + TypeNodeKind::Keyof(_) | TypeNodeKind::Cond { .. } | TypeNodeKind::JSDoc { .. } => { + false + } + TypeNodeKind::Array(of) | TypeNodeKind::Readonly(of) => { + is_resolved_by_check_source_element(hir, of) + } + _ => true, + } +} diff --git a/src/sema/check/context.rs b/src/sema/check/context.rs index 38134f940b87..6e21b826f1f9 100644 --- a/src/sema/check/context.rs +++ b/src/sema/check/context.rs @@ -346,7 +346,23 @@ impl<'p, 's> Checker<'p, 's> { ElemFlags::REQUIRED }); } - Some(self.tuple(&types, &flags, false)) + let result = self.tuple(&types, &flags, false); + if for_context == IncludePatternInType::No { + return Some(result); + } + // `cloneTypeReference`, `patternForType` + Some(self.types().intern_key_with( + TypeKey::Data(self.data(result)), + &ProvenanceKey { + alias: None, + origin: OriginKey::None, + is_enum: false, + stored_under: None, + is_array_literal: false, + is_array_pattern: true, + has_other_instantiation: false, + }, + )) } // `getTypeFromObjectBindingPattern` PatKind::Object(props) => { @@ -411,6 +427,7 @@ impl<'p, 's> Checker<'p, 's> { (shape.literal, shape.is_regular) = (Literalness::Literal, true); } shape.has_no_instantiable_symbol = true; + shape.pattern_at = Some((file, hir[pat].pos)); Some(self.synth(shape)) } } @@ -430,20 +447,25 @@ impl<'p, 's> Checker<'p, 's> { let contextual_type = self .context_implied_by_pattern(file, pat) .unwrap_or(TypeId::UNKNOWN); - let ty = self.check_expression_with_contextual_type( - file, - default, - contextual_type, - None, - CheckMode::empty(), - ); - // `checkDeclarationInitializer`: under a parameter, the type of a default is padded - // with the members its own pattern has defaults for. - let ty = match root_declaration(self.bound(file), pat) { - PatParent::Param(root) => { - self.note_checked_with_contextual_type(file, root, default); - self.padded_for_pattern(file, pat, ty) + // `checkDeclarationInitializer(element, CheckModeNormal, contextualType)` + let root = root_declaration(self.bound(file), pat); + let ty = match self.quick_type_of_expr(file, default) { + Some(quick) => quick, + None => { + if let PatParent::Param(root) = root { + self.note_checked_with_contextual_type(file, root, default); + } + self.check_expression_with_contextual_type( + file, + default, + contextual_type, + None, + CheckMode::empty(), + ) } + }; + let ty = match root { + PatParent::Param(_) => self.padded_for_pattern(file, pat, ty), _ => ty, }; let ty = self.get_widened_literal_type_for_initializer(file, pat, ty); @@ -478,7 +500,7 @@ impl<'p, 's> Checker<'p, 's> { TypeData::Anon { origin: Origin::ObjectLiteral(file, e, ..), .. - } if self.is_definite_assignment_target(file, e) => { + } if self.is_assignment_target(file, e) => { let hir = self.hir(file); let ExprKind::Object(props) = hir[e].kind else { return None; @@ -499,56 +521,9 @@ impl<'p, 's> Checker<'p, 's> { } } - /// Whether `ty` is such a type, or a tuple or a union that contains one. - fn has_pattern_mark(&self, ty: TypeId) -> bool { - match self.data(ty) { - TypeData::Synth(shape) => matches!( - shape.literal, - Literalness::Pattern | Literalness::PatternWithComputedNames - ), - TypeData::Anon { - origin: Origin::ObjectLiteral(file, e, ..), - .. - } => self.is_definite_assignment_target(*file, *e), - // A type from a type node has no mark. - TypeData::Tuple { - elems: TypeArguments::Given(parts), - .. - } - | TypeData::Union(parts) => parts.iter().any(|&p| self.has_pattern_mark(p)), - _ => false, - } - } - - /// `getCovariantInference` ends in `getWidenedType`: an inference from the implied type of a - /// pattern is an ordinary type, which is not in `patternForType`. - fn without_pattern_marks(&mut self, ty: TypeId) -> TypeId { - if self.has_pattern_mark(ty) { - self.get_widened_type(ty) - } else { - ty - } - } - - /// `patternForType[t] != nil` for `t`, the contextual type of `e`. - fn is_expected_by_pattern( - &mut self, - file: FileId, - e: ExprId, - t: TypeId, - context_flags: ContextFlags, - ) -> bool { - if self.pattern_of_type(t).is_some() { - return true; - } - // A tuple carries no mark. It was created from an array pattern if it differs from the - // contextual type computed with binding patterns skipped. - if !self.is_tuple(t) || context_flags.contains(ContextFlags::SKIP_BINDING_PATTERNS) { - return false; - } - let regardless = - self.contextual_type(file, e, context_flags | ContextFlags::SKIP_BINDING_PATTERNS); - regardless != Some(t) + /// `patternForType[t] != nil` + fn is_expected_by_pattern(&mut self, t: TypeId) -> bool { + self.types().is_array_pattern(t) || self.pattern_of_type(t).is_some() } fn type_implied_by_pattern_with_elements( @@ -626,17 +601,7 @@ impl<'p, 's> Checker<'p, 's> { return info.t; } let ty = self.contextual_type_from_parent(file, e, context_flags)?; - if ty == TypeId::UNRESOLVED { - return None; - } - // The contextual type of a call is only used for inference. A call of an immediately - // invoked function passes it on to the function's `return`s. - if let ExprKind::Call(c) | ExprKind::New(c) | ExprKind::TaggedTemplate(c) = hir[e].kind - && !matches!(hir[hir[c].callee].kind, ExprKind::Fn(_)) - { - return Some(self.without_pattern_marks(ty)); - } - Some(ty) + (ty != TypeId::UNRESOLVED).then_some(ty) } fn contextual_type_from_parent( @@ -1772,7 +1737,7 @@ impl<'p, 's> Checker<'p, 's> { let yielded = types.y.unwrap_or(TypeId::SILENT_NEVER); let returned = self .contextual_type(file, parent, context_flags) - .map_or(TypeId::SILENT_NEVER, |t| self.without_pattern_marks(t)); + .unwrap_or(TypeId::SILENT_NEVER); let next = types.n.unwrap_or(TypeId::UNKNOWN); let generator = self.generator_of(yielded, returned, next, false); if is_async { @@ -1810,11 +1775,7 @@ impl<'p, 's> Checker<'p, 's> { // type of the left operand is. BinOp::Or | BinOp::Nullish => { let context = self.contextual_type(file, parent, context_flags); - if e == right - && context.is_none_or(|t| { - self.is_expected_by_pattern(file, parent, t, context_flags) - }) - { + if e == right && context.is_none_or(|t| self.is_expected_by_pattern(t)) { return Some(self.get_type_of_expression(file, left)); } context @@ -1868,7 +1829,6 @@ impl<'p, 's> Checker<'p, 's> { // `getContextualTypeForAwaitOperand` ExprKind::Await(_) => { let context = self.contextual_type(file, parent, context_flags)?; - let context = self.without_pattern_marks(context); self.awaited_or_promise_like(context) } // `getContextualTypeForArgumentAtIndex`: for an `import()`, a string, an @@ -1880,9 +1840,14 @@ impl<'p, 's> Checker<'p, 's> { if hir.ids(args).nth(1) != Some(e) { return Some(TypeId::ANY); } - let name = self.atoms().lookup(b"ImportCallOptions")?; - let sym = self.global_type_symbol(name)?; - Some(self.declared_type(sym)) + // `getGlobalImportCallOptionsType` + let name = self.atoms().lookup(b"ImportCallOptions"); + Some( + match name.and_then(|name| self.get_global_type(name, 0, false)) { + Some(sym) => self.declared_type(sym), + None => TypeId::EMPTY_OBJECT, + }, + ) } // `getContextualTypeForChildJsxExpression` ExprKind::Jsx(j) => { @@ -2006,24 +1971,7 @@ impl<'p, 's> Checker<'p, 's> { return None; } } - // `this.x = value`, where `x` is declared without an annotation: its type comes - // from the assignments. ExprKind::This => { - // In JavaScript the assignment may be the declaration of the property - // (`binary.Symbol != nil`): it has no contextual type, unless the first - // declaration has an annotation (`binary.Symbol.ValueDeclaration.Type()`). - let symbol = bound.symbol_of_declaration(Decl::ThisProperty(assignment)); - if symbol.is_some() - && let Some((of, Decl::ThisProperty(first))) = self - .files() - .value_declaration(self.files().sym(file, symbol)) - && (self.hir(of).jsdoc_type(JsDocTypeOwner::Assign(first))).is_none() - { - return None; - } - if self.declares_member_of_object_literal(file, assignment, obj) { - return None; - } let this = self.get_type_of_expression(file, obj); let this = self.apparent_type(this); let name = match hir[target].kind { @@ -2039,6 +1987,8 @@ impl<'p, 's> Checker<'p, 's> { && let PropSource::Symbol(sym) = prop.source && let Some((of, Decl::Member(m))) = self.files().value_declaration(sym) { + // "No contextual type for 'this.xxx = expr', where xxx is declared as a + // property with no type annotation or initializer." let member = &self.hir(of)[m]; if member.kind == MemberKind::Property && member.ty.is_none() @@ -2047,60 +1997,25 @@ impl<'p, 's> Checker<'p, 's> { return None; } } + // "We have an assignment declaration 'this.xxx = expr' with no (synthetic) type + // annotation" + let symbol = bound.symbol_of_declaration(Decl::ThisProperty(assignment)); + let symbol = bound.computed_symbol_in_table(symbol); + if symbol.is_some() + && let Some((of, declaration)) = self + .files() + .value_declaration(self.files().sym(file, symbol)) + && self.type_node_of_declaration(of, declaration).is_none() + { + return None; + } } _ => {} } } - // `getTypeOfExpression(left)` - Some(self.get_type_of_expression(file, target)) - } - - /// `bindThisPropertyAssignment`, `getThisClassAndSymbolTable`: whether `assignment`, which assigns to a property of `this`, is in - /// a method or an accessor of an object literal in JavaScript. It declares a member of the symbol of the literal then - /// (`binary.Symbol != nil`). Not if a property of that name has a type of its own (`ValueDeclaration.Type() != nil`). - fn declares_member_of_object_literal( - &self, - file: FileId, - assignment: ExprId, - this: ExprId, - ) -> bool { - use crate::bind::{JsDeclarationKind, assignment_declaration_kind}; - let (hir, bound) = (self.hir(file), self.bound(file)); - if assignment_declaration_kind(hir, assignment) != JsDeclarationKind::ThisProperty { - return false; - } - let ExprKind::Assign { target, .. } = hir[assignment].kind else { - return false; - }; - let name = match hir[target].kind { - // `this.#name = value` declares nothing. - ExprKind::Dot { name_pos, .. } if is_private_name_at(hir, name_pos) => { - return false; - } - ExprKind::Dot { name, .. } => name, - _ => Atom::NONE, - }; - let Some(Ok(func)) = self.this_container(file, this) else { - return false; - }; - if !matches!( - hir[func].kind, - FnKind::Method | FnKind::Getter | FnKind::Setter - ) { - return false; - } - let FnOwner::Expr(owner) = bound.fns[func.idx()].owner else { - return false; - }; - let Parent::Prop(p) = bound.expr_parent[owner.idx()] else { - return false; - }; - let ExprKind::Object(props) = hir[bound.prop_owner[p.idx()]].kind else { - return false; - }; - !props.iter().any(|x| { - hir[x].key == PropKey::Name(name) && hir.jsdoc_type(JsDocTypeOwner::Prop(x)).is_some() - }) + let ty = self.get_type_of_expression(file, target); + self.requested_assignment_target = Some((file, target)); + Some(ty) } /// `getContextualTypeForElementExpression`. `length`: the number of elements, if known. diff --git a/src/sema/check/decl.rs b/src/sema/check/decl.rs index da9b4b64010c..57f4ba83ca9e 100644 --- a/src/sema/check/decl.rs +++ b/src/sema/check/decl.rs @@ -402,102 +402,206 @@ impl Evaluated { ..Evaluated::default() } } + + /// The result for a `PrefixUnaryExpression`, from that for its operand. + fn prefix_unary(self, op: UnOp) -> Evaluated { + let value = match (op, self.value) { + (UnOp::Plus, Some(EnumValue::Number(n))) => Some(f64::from_bits(n)), + (UnOp::Minus, Some(EnumValue::Number(n))) => Some(-f64::from_bits(n)), + (UnOp::BitNot, Some(EnumValue::Number(n))) => { + Some(f64::from(!to_int32(f64::from_bits(n)))) + } + _ => None, + }; + Evaluated { + value: value.and_then(|n| Evaluated::number(n).value), + is_syntactically_string: false, + ..self + } + } +} + +/// An expression that `evaluate` has begun: what it goes on with once the operand that is in +/// evaluation has a result. +enum Evaluating { + PrefixUnary(UnOp), + /// The left operand of a `BinaryExpression` is in evaluation, this right one is next. No + /// operator: one that yields no value. + Left(Option, ExprId), + /// The right operand is in evaluation. With the result for the left one. + Right(Option, Evaluated), + /// `evaluateTemplateExpression`: the span at `index` of `exprs` is in evaluation. `text`: what + /// comes before it. + TemplateSpan { + exprs: IdList, + index: usize, + text: Vec, + result: Evaluated, + }, + /// The initializer of a constant is in evaluation, for a use of the constant at this location. + Initializer(Location), +} + +/// What `evaluateEntity` returns. +enum Entity { + Result(Evaluated), + /// The result of `evaluate(declaration.Initializer(), declaration)` for this constant. + Constant(FileId, VarDeclId), } impl<'p, 's> Checker<'p, 's> { /// `evaluate`. `location`: the declaration `e` is evaluated for, the enum member or constant /// whose initializer it is (part of), or else the queried expression. Parentheses are not in - /// the HIR, and nothing else is skipped. + /// the HIR, and nothing else is skipped. It recurses only to compute the values of another + /// enum: constants can refer to one another thousands of times in a row. pub(super) fn evaluate(&mut self, file: FileId, e: ExprId, location: Location) -> Evaluated { if self.is_stack_low() { self.bailed_out(); return Evaluated::default(); } - let hir = self.hir(file); - match hir[e].kind { - // A `PrefixUnaryExpression`, which `typeof`, `void` and `delete` are not. - ExprKind::Unary { - op: - op @ (UnOp::Plus - | UnOp::Minus - | UnOp::BitNot - | UnOp::Not - | UnOp::PreInc - | UnOp::PreDec), - operand, - } => { - let result = self.evaluate(file, operand, location); - let value = match (op, result.value) { - (UnOp::Plus, Some(EnumValue::Number(n))) => Some(f64::from_bits(n)), - (UnOp::Minus, Some(EnumValue::Number(n))) => Some(-f64::from_bits(n)), - (UnOp::BitNot, Some(EnumValue::Number(n))) => { - Some(f64::from(!to_int32(f64::from_bits(n)))) - } - _ => None, - }; - Evaluated { - value: value.and_then(|n| Evaluated::number(n).value), - is_syntactically_string: false, - ..result + let (mut file, mut e, mut location) = (file, e, location); + let mut begun: SmallVec<[Evaluating; 4]> = SmallVec::new(); + 'operand: loop { + let hir = self.hir(file); + let mut result = match hir[e].kind { + // A `PrefixUnaryExpression`, which `typeof`, `void` and `delete` are not. + ExprKind::Unary { + op: + op @ (UnOp::Plus + | UnOp::Minus + | UnOp::BitNot + | UnOp::Not + | UnOp::PreInc + | UnOp::PreDec), + operand, + } => { + begun.push(Evaluating::PrefixUnary(op)); + e = operand; + continue; } - } - ExprKind::Binary { op, left, right } => { - self.evaluate_binary(file, Some(op), left, right, location) - } - // An assignment is a `BinaryExpression` with an operator that yields no value. - ExprKind::Assign { target, value, .. } => { - self.evaluate_binary(file, None, target, value, location) - } - ExprKind::String(text) => Evaluated { - value: Some(EnumValue::String(text)), - is_syntactically_string: true, - ..Evaluated::default() - }, - // `evaluateTemplateExpression` - ExprKind::Template { exprs } => { - let (atoms, texts) = (&self.atoms(), hir.template_texts(exprs)); - let mut text = atoms.bytes(hir.id_at(texts, 0)).to_vec(); - let mut result = Evaluated { + ExprKind::Binary { op, left, right } => { + begun.push(Evaluating::Left(Some(op), right)); + e = left; + continue; + } + // An assignment is a `BinaryExpression` with an operator that yields no value. + ExprKind::Assign { target, value, .. } => { + begun.push(Evaluating::Left(None, value)); + e = target; + continue; + } + ExprKind::String(text) => Evaluated { + value: Some(EnumValue::String(text)), is_syntactically_string: true, ..Evaluated::default() + }, + ExprKind::Template { exprs } => { + let head = hir.id_at(hir.template_texts(exprs), 0); + let result = Evaluated { + is_syntactically_string: true, + ..Evaluated::default() + }; + if !exprs.is_empty() { + begun.push(Evaluating::TemplateSpan { + exprs, + index: 0, + text: self.atoms().bytes(head).to_vec(), + result, + }); + e = hir.id_at(exprs, 0); + continue; + } + Evaluated { + value: Some(EnumValue::String(head)), + ..result + } + } + ExprKind::Number(n) => Evaluated::number(hir.numbers[n as usize]), + ExprKind::Dot { .. } if !is_property_access_entity_name_expression(hir, e) => { + Evaluated::default() + } + ExprKind::Ident(_) | ExprKind::Index { .. } | ExprKind::Dot { .. } => { + match self.evaluate_entity(file, e, location) { + Entity::Result(result) => result, + Entity::Constant(of, d) => { + self.constants_in_evaluation.push((of, d)); + begun.push(Evaluating::Initializer(location)); + (file, e) = (of, self.hir(of)[d].init); + location = Location::Variable(of, d); + continue; + } + } + } + _ => Evaluated::default(), + }; + loop { + let Some(outer) = begun.pop() else { + return result; }; - for (i, span) in hir.ids(exprs).enumerate() { - let of_span = self.evaluate(file, span, location); - let Some(value) = of_span.value else { - return Evaluated { - is_syntactically_string: true, - ..Evaluated::default() + match outer { + Evaluating::PrefixUnary(op) => result = result.prefix_unary(op), + Evaluating::Left(op, right) => { + begun.push(Evaluating::Right(op, result)); + e = right; + continue 'operand; + } + Evaluating::Right(op, left) => result = self.evaluate_binary(op, left, result), + Evaluating::TemplateSpan { + exprs, + index, + mut text, + result: mut of_template, + } => { + let Some(value) = result.value else { + result = Evaluated { + is_syntactically_string: true, + ..Evaluated::default() + }; + continue; }; - }; - text.extend_from_slice(self.constant_text(value)); - text.extend_from_slice(atoms.bytes(hir.id_at(texts, i + 1))); - result.resolved_other_files |= of_span.resolved_other_files; - result.has_external_references |= of_span.has_external_references; + let (hir, index) = (self.hir(file), index + 1); + let literal = hir.id_at(hir.template_texts(exprs), index); + text.extend_from_slice(self.constant_text(value)); + text.extend_from_slice(self.atoms().bytes(literal)); + of_template.resolved_other_files |= result.resolved_other_files; + of_template.has_external_references |= result.has_external_references; + if index < exprs.len() { + e = hir.id_at(exprs, index); + begun.push(Evaluating::TemplateSpan { + exprs, + index, + text, + result: of_template, + }); + continue 'operand; + } + of_template.value = Some(EnumValue::String(self.atoms().intern(&text))); + result = of_template; + } + Evaluating::Initializer(used_at) => { + self.constants_in_evaluation.pop(); + result = if used_at.file() != file { + Evaluated { + value: result.value, + is_syntactically_string: false, + resolved_other_files: true, + has_external_references: true, + } + } else { + Evaluated { + has_external_references: true, + ..result + } + }; + (file, location) = (used_at.file(), used_at); + } } - result.value = Some(EnumValue::String(atoms.intern(&text))); - result - } - ExprKind::Number(n) => Evaluated::number(hir.numbers[n as usize]), - ExprKind::Ident(_) | ExprKind::Index { .. } => self.evaluate_entity(file, e, location), - ExprKind::Dot { .. } if is_property_access_entity_name_expression(hir, e) => { - self.evaluate_entity(file, e, location) } - _ => Evaluated::default(), } } - fn evaluate_binary( - &mut self, - file: FileId, - op: Option, - left: ExprId, - right: ExprId, - location: Location, - ) -> Evaluated { - let (l, r) = ( - self.evaluate(file, left, location), - self.evaluate(file, right, location), - ); + /// The result for a `BinaryExpression`, from those for its operands. + fn evaluate_binary(&self, op: Option, l: Evaluated, r: Evaluated) -> Evaluated { let value = match (l.value, r.value, op) { (Some(EnumValue::Number(a)), Some(EnumValue::Number(b)), Some(op)) => { number_operation(op, f64::from_bits(a), f64::from_bits(b)) @@ -519,31 +623,31 @@ impl<'p, 's> Checker<'p, 's> { } /// `evaluateEntity`: by the symbols the names resolve to, never by the type of the expression. - fn evaluate_entity(&mut self, file: FileId, e: ExprId, location: Location) -> Evaluated { + fn evaluate_entity(&mut self, file: FileId, e: ExprId, location: Location) -> Entity { let (hir, files) = (self.hir(file), self.files()); + let no_value = Entity::Result(Evaluated::default()); if let ExprKind::Index { obj, index, .. } = hir[e].kind { let name = match hir[index].kind { ExprKind::String(name) => name, ExprKind::Template { exprs } if exprs.is_empty() => { hir.id_at(hir.template_texts(exprs), 0) } - _ => return Evaluated::default(), + _ => return no_value, }; // Neither `(a)["b"]` nor `a[("b")]`. if is_parenthesized(hir, index) || !is_entity_name_expression(hir, obj) { - return Evaluated::default(); + return no_value; } if let Some(root) = self.resolve_entity_name_expression(file, obj, SymFlags::VALUE) && files.flags(root).intersects(SymFlags::ENUM) && let Some(member) = files.export(root, name) - && files.flags(member).contains(SymFlags::ENUM_MEMBER) { - return self.evaluate_enum_member(file, e, member, location); + return Entity::Result(self.evaluate_enum_member(file, e, member, location)); } - return Evaluated::default(); + return no_value; } let Some(symbol) = self.resolve_entity_name_expression(file, e, SymFlags::VALUE) else { - return Evaluated::default(); + return no_value; }; // `Infinity` and `NaN`, unless they are shadowed. if let ExprKind::Ident(name) = hir[e].kind @@ -554,33 +658,19 @@ impl<'p, 's> Checker<'p, 's> { } && files.global(name, SymFlags::VALUE) == Some(symbol) { - return Evaluated::number(n); + return Entity::Result(Evaluated::number(n)); } if files.flags(symbol).contains(SymFlags::ENUM_MEMBER) { - return self.evaluate_enum_member(file, e, symbol, location); + return Entity::Result(self.evaluate_enum_member(file, e, symbol, location)); } // There is no declaration order between files: constants of two files may be initialized // with each other. - if let Some((of, d)) = self.constant_variable_declaration(symbol, location) - && !self.constants_in_evaluation.contains(&(of, d)) - { - self.constants_in_evaluation.push((of, d)); - let result = self.evaluate(of, self.hir(of)[d].init, Location::Variable(of, d)); - self.constants_in_evaluation.pop(); - if location.file() != of { - return Evaluated { - value: result.value, - is_syntactically_string: false, - resolved_other_files: true, - has_external_references: true, - }; + match self.constant_variable_declaration(symbol, location) { + Some((of, d)) if !self.constants_in_evaluation.contains(&(of, d)) => { + Entity::Constant(of, d) } - return Evaluated { - has_external_references: true, - ..result - }; + _ => no_value, } - Evaluated::default() } /// `evaluateEnumMember` @@ -591,27 +681,24 @@ impl<'p, 's> Checker<'p, 's> { symbol: Sym, location: Location, ) -> Evaluated { - // `symbol.ValueDeclaration` - let declaration = self - .files() - .decls_of(symbol) - .iter() - .find_map(|&(of, decl)| match decl { - Decl::EnumMember(member) => Some((of, member)), - _ => None, - }); - let Some((of, member)) = - declaration.filter(|&(of, member)| Location::Member(of, member) != location) - else { + let used = (location.file(), location.node(self.hir(location.file()))); + let declaration = self.files().value_declaration(symbol); + let declaration = declaration.map(|(of, decl)| (decl, (of, self.hir(of).node(decl)))); + let Some((declaration, declared @ (of, _))) = declaration.filter(|it| it.1 != used) else { let at = self.place_of_expr(file, e); self.error_at(at, 2565, &[Arg::Sym(symbol)]); return Evaluated::default(); }; - if !is_declared_before_use(self, Location::Member(of, member), location) { + if !is_declared_before_use(self, declared, location) { let at = self.place_of_expr(file, e); self.error_at(at, 2651, &[]); return Evaluated::number(0.0); } + // `E["x"]` is any export of `E`. `getEnumMemberValue` of what a merged namespace exports + // panics. + let Decl::EnumMember(member) = declaration else { + return Evaluated::default(); + }; let value = self.enum_member_value_at(of, member, location); // `location.Parent != declaration.Parent` let owner = &self.bound(of).enum_member_owner; @@ -1086,18 +1173,7 @@ impl<'p, 's> Checker<'p, 's> { candidates: self.type_param_names_in_scope(file, scope), ..Mentioned::default() }; - // `containsReference` - let mut left = vec![hir.node(e)]; - while let Some(node) = left.pop() { - if let NodeData::Type(written) = hir.data(node) { - self.collect_mentions(file, written, &mut mentioned); - continue; - } - hir.for_each_child(node, &mut |child| { - left.push(child); - false - }); - } + self.collect_mentions_in_node(file, hir.node(e), &mut mentioned); declared = self.identity_mapper_of_mentioned(file, scope, hir[e].pos, &mentioned); } self.with_adopted_type_params(declared, file, scope, hir[e].pos) @@ -1310,23 +1386,30 @@ impl<'p, 's> Checker<'p, 's> { /// `containsReference` for a node that need not be a type node. fn collect_mentions_in_node(&self, file: FileId, node: Node, out: &mut Mentioned) { - if out.everything { - return; - } let hir = self.hir(file); - let is_method = match hir.data(node) { - NodeData::Type(t) => return self.collect_mentions(file, t, out), - NodeData::Member(m) => hir[m].kind == MemberKind::Method, - NodeData::Prop(p) => hir[p].kind == PropKind::Method, - _ => false, - }; - if is_method && hir.function_of(node).is_some() { - return self.collect_fn_mentions(file, hir.function_of(node), out); + let mut left = SmallVec::<[Node; 16]>::new(); + left.push(node); + while let Some(node) = left.pop() + && !out.everything + { + let is_method = match hir.data(node) { + NodeData::Type(t) => { + self.collect_mentions(file, t, out); + continue; + } + NodeData::Member(m) => hir[m].kind == MemberKind::Method, + NodeData::Prop(p) => hir[p].kind == PropKind::Method, + _ => false, + }; + if is_method && hir.function_of(node).is_some() { + self.collect_fn_mentions(file, hir.function_of(node), out); + continue; + } + hir.for_each_child(node, &mut |child| { + left.push(child); + false + }); } - hir.for_each_child(node, &mut |child| { - self.collect_mentions_in_node(file, child, out); - out.everything - }); } fn collect_mentions(&self, file: FileId, node: TypeNodeId, out: &mut Mentioned) { @@ -1341,12 +1424,12 @@ impl<'p, 's> Checker<'p, 's> { }; match hir[node].kind { TypeNodeKind::Error - | TypeNodeKind::Heritage(_) | TypeNodeKind::StringLit(_) | TypeNodeKind::NumberLit(_) | TypeNodeKind::BigIntLit { .. } | TypeNodeKind::BoolLit(_) | TypeNodeKind::UniqueSymbol => {} + TypeNodeKind::Heritage { args, .. } => list(self, args, out), TypeNodeKind::Keyword(keyword) => out.this |= keyword == Keyword::This, TypeNodeKind::Ref { name, args } => { if name.len() == 1 && args.is_empty() { @@ -1770,7 +1853,7 @@ impl<'p, 's> Checker<'p, 's> { /// declaration. Those with the same name in the declarations of a class or an interface are one /// type parameter: a result from another declaration is returned with the type parameters of /// that declaration and of this one. - fn type_param_declaration_with( + pub(super) fn type_param_declaration_with( &self, file: FileId, tp: TypeParamId, @@ -1852,6 +1935,8 @@ impl<'p, 's> Checker<'p, 's> { /// `instantiateSignatureEx`, the mapper assigned to a cloned type parameter: the mappings of /// `around`, plus the clones for the type parameters declared in the same list as `tp`. + /// `getUniqueTypeParameters`: its mapper has the renamed type parameters only. The others are + /// the clones for `around` without the new names. fn clone_mapper(&self, file: FileId, tp: TypeParamId, around: MapperId) -> MapperId { let (hir, bound) = (self.hir(file), self.bound(file)); let scope = bound.type_param_scope[tp.idx()]; @@ -1861,14 +1946,27 @@ impl<'p, 's> Checker<'p, 's> { Some(ScopeKind::Interface(i)) => hir[i].type_params, _ => Span::new(tp.0, 1), }; + let mapping = self.types().mapping(around); + let is_new_name = + |pair: &(TypeId, TypeId)| matches!(self.data(pair.0), TypeData::StringLit { .. }); + let before_renaming = if mapping.iter().any(is_new_name) { + let kept = (mapping.iter().copied()) + .filter(|pair| !is_new_name(pair)) + .collect(); + self.types().mapper(kept) + } else { + around + }; let fresh: SmallVec<[(TypeId, TypeId); 4]> = list .iter() .map(|t| { let declared = self.type_param(file, t); + let keeps_name = before_renaming != around + && self.new_type_param_name(hir[t].name, around).is_none(); + let around = if keeps_name { before_renaming } else { around }; (declared, self.cloned_type_param(file, t, around)) }) .collect(); - let mapping = self.types().mapping(around); let mut pairs = Vec::with_capacity(mapping.len() + fresh.len()); pairs.extend( mapping @@ -2235,6 +2333,12 @@ impl<'p, 's> Checker<'p, 's> { } Err(open) => self.cache_provisionally(Query::Declared(sym), u64::from(ty.0), open), } + // `getDeclaredTypeOfClassOrInterface` asks `isThislessInterface` once `links.declaredType` + // is assigned: in a cycle of `extends` the answers depend on which interface is created + // first. + if self.files().flags(sym).contains(SymFlags::INTERFACE) { + self.has_this_type(sym); + } ty } @@ -2585,11 +2689,10 @@ impl<'p, 's> Checker<'p, 's> { let PatParent::Var(d) = self.bound(of).pat_parent[pat.idx()] else { return None; }; - let declaration = &self.hir(of)[d]; - let declared = Location::Variable(of, d); + let (declaration, declared) = (&self.hir(of)[d], (of, self.hir(of).node(d))); (declaration.ty.is_none() && declaration.init.is_some() - && declared != location + && Location::Variable(of, d) != location && is_declared_before_use(self, declared, location)) .then_some((of, d)) } @@ -2608,7 +2711,7 @@ impl<'p, 's> Checker<'p, 's> { // `resolveName(e, name, meaning)`. The binder has already resolved the value meaning of // an identifier. ExprKind::Ident(name) if meaning == SymFlags::VALUE => { - self.symbol_of_identifier(file, e, name)? + self.resolve_identifier(file, e, name, false).ok()?? } ExprKind::Ident(name) => { let scope = self.enclosing_scope_of_expr(file, e); @@ -2662,6 +2765,9 @@ impl<'p, 's> Checker<'p, 's> { let ty = self.type_from_node_uncached(file, node); let ty = self.conditional_flow_type_of_type(file, ty, node); let ty = self.with_alias_for_type_node(file, node, ty); + if self.is_innermost_tainted() { + self.keep_type_of_annotation_in_cycle(ty); + } match self.leave(Query::TypeNode(file, node)) { // Where the node was in progress several times, the outermost is the last to store. Ok(stored) => { @@ -2676,6 +2782,43 @@ impl<'p, 's> Checker<'p, 's> { ty } + /// `getTypeFromTypeNode` assigns `links.resolvedType` whatever is in progress. Where + /// `popTypeResolution` finds a cycle, `getTypeOfAccessors`, `getWriteTypeOfAccessors` and + /// `getReturnTypeOfSignature` resolve to `anyType`, and their annotation keeps what followed + /// from the `errorType` of the `pushTypeResolution` that failed. Computed again it would follow + /// from `anyType`. So the innermost frame, of a type node that resolves to `ty`, is final if it + /// is directly under such a resolution and depends on no more than cycles. + #[cold] + #[inline(never)] + fn keep_type_of_annotation_in_cycle(&mut self, ty: TypeId) { + let [.., resolution, annotation] = &self.frames[..] else { + return; + }; + let since = |at: u64| at >= annotation.serial; + if !resolution.circular + || annotation.incomplete_flow + || since(self.limit_at) + || since(self.refused_at) + || since(self.any_signature_read_at) + || !self.inference_contexts.is_empty() + || (self.types().object_flags(ty)).contains(ObjectFlags::HAS_UNRESOLVED) + { + return; + } + let resolves_to_any = match self.stack[self.stack.len() - 2] { + Query::Return(..) + | Query::ReturnOfSignature(_) + | Query::WriteType(..) + | Query::LiteralProp(..) => true, + Query::Symbol(symbol) => self.files().flags(symbol).intersects(SymFlags::ACCESSOR), + _ => false, + }; + if resolves_to_any && let Some(annotation) = self.frames.last_mut() { + annotation.tainted = false; + annotation.drops_reported = false; + } + } + /// `globalReadonlyArrayType`, which is `globalArrayType` if there is no `ReadonlyArray`, or /// `globalArrayType`. `None`: `emptyGenericType`. fn global_array_type(&self, readonly: bool) -> Option { @@ -2825,7 +2968,7 @@ impl<'p, 's> Checker<'p, 's> { let hir = self.hir(file); let scope = self.bound(file).type_scope[node.idx()]; match hir[node].kind { - TypeNodeKind::Error | TypeNodeKind::Heritage(_) => TypeId::UNRESOLVED, + TypeNodeKind::Error | TypeNodeKind::Heritage { .. } => TypeId::UNRESOLVED, TypeNodeKind::Keyword(k) => match k { Keyword::Any => TypeId::ANY, Keyword::Unknown => TypeId::UNKNOWN, @@ -3069,7 +3212,11 @@ impl<'p, 's> Checker<'p, 's> { if is_typeof { let ty = self.type_of_alias_target(symbol); // `getInstantiationExpressionType`: `typeArguments == nil` - if args.is_empty() { + if args.is_empty() + && self + .empty_type_argument_list_of_import_type(file, node) + .is_none() + { return ty; } let args = self.types_from_nodes(file, args); @@ -3160,7 +3307,7 @@ impl<'p, 's> Checker<'p, 's> { next = Some(AliasTarget::Property( ty, text, - self.type_of_prop(prop, mapper), + Some(self.type_of_prop(prop, mapper)), )); } } @@ -3189,7 +3336,7 @@ impl<'p, 's> Checker<'p, 's> { ) -> Option { let found = self.resolve_entity_name(file, scope, name, SymFlags::TYPE, ignore_errors)?; // `resolveEntityName` resolves an alias to the first symbol in the chain that has a type meaning. - let target = match self.combined_symbol_of_alias(found) { + let target = match self.combined_symbol_of_resolved_alias(found) { Some(combined) => combined, None => self.files().resolve_alias_as(found, SymFlags::TYPE)?, }; @@ -3287,7 +3434,10 @@ impl<'p, 's> Checker<'p, 's> { return Some(most); } let at = match node { - Ok(node) => (file, hir[node].pos, self.end_of_type_node(file, node)), + Ok(node) => { + let (start, end) = self.get_error_range_for_node(file, hir.node(node)); + (file, start, end) + } // Type arguments from an `@extends` tag are located elsewhere in the source. Err(class) => { let start = self.start_of(file, hir[class].extends); @@ -3324,18 +3474,7 @@ impl<'p, 's> Checker<'p, 's> { }; let name = if is_class_or_interface { let declared = self.declared_type(sym); - // `TypeFormatFlagsWriteArrayAsGenericType` - match self.array_element(declared) { - Some(element) => { - cat!( - self.symbol_to_string(sym), - b"<", - self.type_to_string(element), - b">" - ) - } - None => self.type_to_string(declared), - } + self.type_to_string_with_generic_arrays(declared) } else { self.symbol_to_string(sym) }; @@ -3475,8 +3614,7 @@ impl<'p, 's> Checker<'p, 's> { Some(sym) if self.has_this_type(sym) => self.intern(TypeData::ThisParam(sym)), Some(_) => TypeId::ERROR, None => { - let at = self.place_of_token(file, self.hir(file)[node].pos); - self.error_at(at, 2526, &[]); + self.error(file, node, 2526, &[]); TypeId::ERROR } } @@ -3637,8 +3775,8 @@ impl<'p, 's> Checker<'p, 's> { Some(alias) } - /// `type_reference` for a type reference node. - fn type_reference_of_node(&mut self, sym: Sym, args: &[TypeId]) -> TypeId { + /// `type_reference` for a type reference node, or for the `extends` clause of a class. + pub(super) fn type_reference_of_node(&mut self, sym: Sym, args: &[TypeId]) -> TypeId { if !self .files() .flags(sym) @@ -4169,8 +4307,15 @@ impl<'p, 's> Checker<'p, 's> { { return false; } - let crate::bind::FnOwner::Expr(e) = bound.fns[func.idx()].owner else { - return true; + // The parent of a method or an accessor of an object literal is the literal, for which + // `getContextualType` has no case. + let e = match bound.fns[func.idx()].owner { + crate::bind::FnOwner::Expr(e) + if matches!(hir[func].kind, FnKind::Expr | FnKind::Arrow) => + { + e + } + _ => return true, }; if let Some(known) = (self.p.untyped_signatures_in_js).get(&self.task, &(file, func)) { return known; @@ -4210,6 +4355,66 @@ impl<'p, 's> Checker<'p, 's> { params } + /// The same request for `getParameterCount` and `getEffectiveRestType`, which resolve the type + /// of a rest parameter and of no other. + pub(super) fn request_type_of_rest_parameter(&mut self, sig: SigId) { + if self.recent_sig_params[sig.0 as usize % RECENT_SIGS].0 != sig + && let Some(declared) = self.default_construct_base_sig(sig) + && let SigData::Decl { file, func, .. } | SigData::Construct { file, func, .. } = + *self.types().sig(declared) + && let Some(rest) = self.hir(file)[func].params.iter().next_back() + && self.hir(file)[rest].flags.contains(Flags::REST) + && self.p.sig_params.get_ref(&self.task, &declared).is_none() + { + self.type_of_param(file, rest); + } + } + + /// `sig_params_up_to` for `assignContextualParameterTypes(.., sig)`: tsgo requests the type at + /// the position of every parameter of `func` that has no annotation (`tryGetTypeAtPosition`, + /// `getRestTypeAtPosition`), while `c.currentNode` is `func`. + pub(super) fn sig_params_assigned_to( + &mut self, + sig: SigId, + file: FileId, + func: FnId, + ) -> List<'p, SigParam> { + if self.recent_sig_params[sig.0 as usize % RECENT_SIGS].0 != sig + && let Some(declared) = self.default_construct_base_sig(sig) + && let SigData::Decl { + file: of, + func: context, + .. + } = *self.types().sig(declared) + && self.p.sig_params.get_ref(&self.task, &declared).is_none() + { + let (hir, declaring) = (self.hir(file), self.hir(of)); + let (own, params) = (hir[func].params, declaring[context].params); + let rest = params.iter().next_back(); + let rest = rest.filter(|&p| declaring[p].flags.contains(Flags::REST)); + for (i, p) in own.iter().enumerate() { + if hir[p].ty.is_some() { + continue; + } + let is_rest = hir[p].flags.contains(Flags::REST) && i + 1 == own.len(); + let end = if is_rest { params.len() } else { 0 }; + for position in i..end.max(i + 1) { + if let Some(parameter) = params.iter().nth(position).or(rest) { + self.type_of_param(of, parameter); + } + } + } + } + self.sig_params(sig) + } + + /// The same request for one parameter of a list that `sig_params` could not store. + pub(super) fn request_type_of_parameter(&mut self, parameter: &SigParam) { + if let Some((file, p)) = parameter.declaration { + self.type_of_param(file, p); + } + } + /// tsgo has assigned `links.resolvedType` of the first `count` of `params`, the parameters of /// `sig`. Recorded for those about which `is_parameter_type_resolved` is asked: `sig` is an /// instantiation that has type parameters, and its mapper has left no type variable in a type @@ -4335,6 +4540,26 @@ impl<'p, 's> Checker<'p, 's> { List::Own(params.to_vec()) } + /// `getSignatureFromDeclaration`: "Include parameter symbol instead of property symbol in the + /// signature". `param.Symbol()` of a parameter property is the property, so `resolveName` looks + /// its name up from `param`, in the locals of the constructor `func`: that is the first + /// parameter of that name. Returns the declaration of the symbol in the signature. + fn declaration_of_parameter_symbol(&self, file: FileId, func: FnId, param: ParamId) -> ParamId { + let (hir, bound) = (self.hir(file), self.bound(file)); + if hir[param].flags.contains(Flags::PARAMETER_PROPERTY) + && hir[func].kind == FnKind::Constructor + && let PatKind::Ident(name) = hir[hir[param].pat].kind + && let locals = bound.scopes[bound.fns[func.idx()].scope.idx()].locals + && let Some(resolved) = bound.lookup(locals, name) + && let resolved = &bound.symbols[resolved.idx()] + && let Some(&Decl::Param(pat)) = resolved.decls.get(resolved.value_declaration as usize) + && let PatParent::Param(declaration) = bound.pat_parent[pat.idx()] + { + return declaration; + } + param + } + /// `target`: see `instantiated_target`. #[inline(never)] fn sig_params_of_declaration( @@ -4361,12 +4586,15 @@ impl<'p, 's> Checker<'p, 's> { ); // `instantiateSignatureEx` instantiates the parameters of `signature.target`. let target = target.map(|target| (target, self.sig_params(target))); - for (i, p) in hir[func].params.iter().enumerate() { - let param = &hir[p]; + for (i, node) in hir[func].params.iter().enumerate() { + let param = &hir[node]; let name = match hir[param.pat].kind { PatKind::Ident(name) => name, _ => Atom::NONE, }; + // `paramSymbol.ValueDeclaration` + let p = self.declaration_of_parameter_symbol(file, func, node); + let value_declaration = &hir[p]; // TypeScript resolves the type of a parameter when there is an argument to check // against it. // The one caller of an immediately invoked function expression has `actual` of them. @@ -4385,8 +4613,11 @@ impl<'p, 's> Checker<'p, 's> { && !param.flags.contains(Flags::REST); let optional = param.flags.contains(Flags::OPTIONAL) || param.default.is_some() || is_omitted; - // For callers, an optional parameter also accepts `undefined`. - let declared = if optional { + // `getTypeOfParameter`: for callers, an optional parameter also accepts `undefined`. + let declared = if value_declaration.flags.contains(Flags::OPTIONAL) + || value_declaration.default.is_some() + || is_omitted + { self.optional(declared) } else { declared @@ -4394,9 +4625,9 @@ impl<'p, 's> Checker<'p, 's> { // `instantiateSymbol` returns a symbol that `isThisless` itself, whatever its type is: // `isThislessVariableLikeDeclaration`. let is_kept = maps_this_only - && match param.ty.is_some() { - true => super::errors_unused::is_thisless_type(hir, param.ty), - false => param.default.is_none(), + && match value_declaration.ty.is_some() { + true => super::errors_unused::is_thisless_type(hir, value_declaration.ty), + false => value_declaration.default.is_none(), }; let mut ty = if is_kept { declared @@ -4579,7 +4810,15 @@ impl<'p, 's> Checker<'p, 's> { SigData::WithReturn { sig: inner, .. } => return self.sig_predicate(inner), SigData::Synth { ref of, is_union, .. - } if of.len() > 1 => return self.union_or_intersection_type_predicate(of, is_union), + } => { + return match of[..] { + [] => None, + // `cloneSignature`, `instantiateSignatureEx`: the declaration, the target and + // the mapper are those of the signature it was made from. + [only] => self.sig_predicate(only), + _ => self.union_or_intersection_type_predicate(of, is_union), + }; + } SigData::Decl { file, func, mapper } => (file, func, mapper), _ => return None, }; @@ -4595,8 +4834,9 @@ impl<'p, 's> Checker<'p, 's> { let TypeNodeKind::Predicate { param, ty, asserts } = hir[f.ret].kind else { return None; }; - // `IsTypePredicateNode(typeNode)`: a `ParenthesizedType`, which has no node, is none. - if (self.parenthesized_types_around(file, f.ret, f.start)) + // `IsTypePredicateNode(typeNode)`: a `ParenthesizedType`, which has no node, is none. The + // type of a `@returns` tag comes before the function. + if (self.parenthesized_types_around(file, f.ret, 0)) .next() .is_some() { @@ -4709,13 +4949,16 @@ impl<'p, 's> Checker<'p, 's> { Some(self.rest_element_type(rest, offset)) } - /// The type of element `offset` of the array or tuple type a rest parameter is declared with. + /// `getIndexedAccessType(rest, getNumberLiteralType(offset))` for the type `rest` of a rest + /// parameter. FOR SPEED: an array or a tuple is not searched for a property named `offset`, + /// unless an array can have one that is not an element. pub fn rest_element_type(&mut self, rest: TypeId, offset: usize) -> TypeId { - if let Some(element) = self.array_element(rest) { + let has_elements_only = !self.files().arrays_have_numeric_members; + if has_elements_only && let Some(element) = self.array_element(rest) { return element; } match self.data(rest) { - TypeData::Tuple { flags, .. } => { + TypeData::Tuple { flags, .. } if has_elements_only => { let elems = self.type_arguments(rest); if let Some(&e) = elems.get(offset) && !flags[..=offset] diff --git a/src/sema/check/decorators.rs b/src/sema/check/decorators.rs index 0da904606084..2cc9bd256d1a 100644 --- a/src/sema/check/decorators.rs +++ b/src/sema/check/decorators.rs @@ -386,13 +386,9 @@ impl<'p, 's> Checker<'p, 's> { let text = self.atoms().intern(self.written_name(name)); self.string_literal(text, false) } - // `getLiteralTypeFromPropertyName`, which has no text for a name that declares nothing. - _ => match self.literal_type_from_property_name(file, key, name_kind) { - Some(name_type) => name_type, - None => self - .get_property_name_for_property_name_node(file, key, member.name_pos) - .map_or(TypeId::NEVER, |text| self.string_literal(text, false)), - }, + _ => self + .literal_type_from_property_name(file, key, name_kind, member.name_pos) + .unwrap_or(TypeId::NEVER), }; let context: &[u8] = match member.kind { MemberKind::Method => b"ClassMethodDecoratorContext", diff --git a/src/sema/check/errors.rs b/src/sema/check/errors.rs index 4ffc89857d8d..c337d3b9f782 100644 --- a/src/sema/check/errors.rs +++ b/src/sema/check/errors.rs @@ -65,9 +65,22 @@ impl Program<'_> { // task evaluated them. let is_checked = |d: &Reported| { let mut never_checked = checked.never_checked.iter(); - d.by_emit || !never_checked.any(|&(from, to)| (from..to).contains(&d.start)) + d.by_emit + || d.by_another_node + || !never_checked.any(|&(from, to)| (from..to).contains(&d.start)) }; out.extend(self.take_buffer(file).into_iter().filter(is_checked)); + // `requestedExternalEmitHelpers`: first come, whichever file was being checked. + if self.files.options.import_helpers { + let earlier = self.emit_helper_errors_of_earlier_files.lock(); + out.retain(|d| { + let same = earlier + .iter() + .filter(|it| (it.file, it.code) == (file, d.code) && it.args == d.args); + let first = same.min_by_key(|it| it.rank); + first.is_none_or(|first| first.start == d.start) + }); + } if !checked.unused_private_members.is_empty() { let referenced = self.properties_referenced_before.lock(); let mut unused = checked.unused_private_members; @@ -146,9 +159,12 @@ impl Checker<'_, '_> { self.rechecked_exprs.retain(|key, _| key.0 != file); self.rechecked_members.retain(|key, _| key.0 != file); self.late_bound_members.retain(|key, _| key.0.file != file); + self.early_bound_for_good.retain(|key| key.0.file != file); self.resolved_signatures.retain(|key| key.0 != file); self.context_checked_here.retain(|key| key.0 != file); self.prepared.retain(|key| key.0 != file); + self.circular_before_parameter_symbol + .retain(|key| key.0 != file); } /// Runs every check that queries `file`. Diagnostics it causes in other files, or other files @@ -174,12 +190,13 @@ impl Checker<'_, '_> { self.variances_cut_short.clear(); self.generic_mapped_types_cut_short.clear(); self.deferred_diagnostics.clear(); - // Entries the task's previous file added after its own `check_circular_mapped_properties` - // are dropped, as they are for the last file. - self.circular_mapped_props.clear(); self.node_check_flags.clear(); self.never_checked.borrow_mut().clear(); self.unknown_symbols.clear(); + self.alias_targets_reported.clear(); + self.signatures_resolved_discarding.clear(); + self.expressions_cached_discarding.clear(); + self.emit_helpers_checked_elsewhere.clear(); self.reported.clear(); self.release_provisional_shapes(); self.is_type_checked = false; @@ -271,7 +288,7 @@ impl Checker<'_, '_> { self.mark_identifier_aliases_referenced(file, true); } self.produce_type_not_iterable_errors(logged); - self.check_circular_mapped_properties(); + self.resolve_marked_assignment_targets(file); self.report_unresolved_identifiers(); // `GetDeclarationDiagnostics`: no comment directive suppresses these, and plain JavaScript // gets them too. @@ -282,6 +299,7 @@ impl Checker<'_, '_> { self.log_reported_from(0); let emits_later = !self.emits_first(); let was_emitting = self.set_symbol_ids_emitting(emits_later); + self.is_type_checked = emits_later; let declaration = self.get_declaration_diagnostics(file); self.set_symbol_ids_emitting(was_emitting); self.is_type_checked = true; @@ -370,6 +388,7 @@ impl Checker<'_, '_> { return None; } self.settle_place(&mut d); + d.start = super::spans::start_of_error_range(hir, d.start, d.end); Some(d) } @@ -452,7 +471,7 @@ impl Checker<'_, '_> { let ExprKind::ImportCall { args, .. } = hir[e].kind else { continue; }; - if self.bound(file).is_unchecked(e.idx()) { + if self.bound(file).is_unchecked(e.idx()) || self.is_never_checked(hir[e].pos) { continue; } if let Some(options) = hir.ids(args).nth(1) { @@ -511,18 +530,37 @@ impl Checker<'_, '_> { if !declares_alias && !self.is_commonjs_require(file, call) { continue; } - let mode = self.require_resolution_mode(file, spec); - let written = SpecifierUse { - spec, - pos: hir[argument].pos, - kind: SpecifierKind::RequireCall, - mode, - }; - self.resolve_external_module(file, written, SpecifierSite::default()); + self.resolve_required_module(file, argument, spec); } } } + /// `resolveExternalModuleName` for `argument`, the argument of `require(spec)`: whether the + /// module is found. + fn resolve_required_module(&mut self, file: FileId, argument: ExprId, spec: Atom) -> bool { + let written = SpecifierUse { + spec, + pos: self.hir(file)[argument].pos, + kind: SpecifierKind::RequireCall, + mode: self.require_resolution_mode(file, spec), + }; + self.resolve_external_module(file, written, SpecifierSite::default()) + } + + /// The same for the module that the variable declaration or the binding element with the name + /// `name` is initialized to (`getTargetOfImportEqualsDeclaration`, `getExternalModuleMember`). + pub(super) fn resolve_module_required_by(&mut self, file: FileId, name: PatId) -> bool { + let PatParent::Var(decl) = root_declaration(self.bound(file), name) else { + return false; + }; + let Some((argument, spec)) = self.external_module_require_argument(file, decl) else { + return false; + }; + // The loader only resolves the specifiers that the binder collected. + self.bound(file).specifiers.contains(&spec) + && self.resolve_required_module(file, argument, spec) + } + /// What `checkImportCallExpression` does with `options`, the second argument. fn check_import_call_options(&mut self, file: FileId, options: ExprId) { let hir = self.hir(file); @@ -658,7 +696,7 @@ impl Checker<'_, '_> { } // `reportNonExportedMember` (2459 | 2460, _) => { - let local = self.local_of_module(module, name); + let local = self.files().local_of_module(module, name); let declarations = local.map(|local| self.files().decls_of(local)); for (i, &(of, decl)) in declarations.iter().flat_map(|it| it.iter()).enumerate() { if let Some(place) = self.error_place_of_declaration(of, decl) { @@ -685,21 +723,6 @@ impl Checker<'_, '_> { self.error_at(at, code, args).related_information = related; } - /// `moduleSymbol.ValueDeclaration.Locals()[name]`: a local declaration of the file, or of the - /// first `declare module "m"`. - fn local_of_module(&self, module: Sym, name: Atom) -> Option { - let files = self.files(); - let &(of, decl) = files.decls_of(module).first()?; - let bound = files.bound(of); - let scope = match decl { - Decl::File => 0, - Decl::Module(m) => bound.module_scope[m.idx()].idx(), - _ => return None, - }; - let local = bound.lookup(bound.scopes.get(scope)?.locals, name)?; - Some(files.sym(of, local)) - } - /// `reportNonDefaultExport`: the first `export *` of `module` that targets a module with a /// default export, which is not re-exported. fn export_star_past_a_default(&self, module: Sym) -> Option<(FileId, u32, u32)> { @@ -801,19 +824,22 @@ impl Checker<'_, '_> { if files.export(module, known::default).is_some() { return (2614, None); } - let Some(local) = self.local_of_module(module, name) else { + let Some(local) = files.local_of_module(module, name) else { return (2305, None); }; - let local = self.merged_resolved_symbol(local); + // `getSymbolIfSameReference` + let is_local = |c: &mut Self, exported: Sym| { + c.merged_resolved_symbol(exported) == c.merged_resolved_symbol(local) + }; let Some(equals) = files.export(module, known::export_equals) else { let own = files.exports(module); let mut own = own.iter(); - return match own.find(|&&(_, e)| self.merged_resolved_symbol(e) == local) { + return match own.find(|&&(_, exported)| is_local(self, exported)) { Some(&(_, exported)) => (2460, Some(exported)), None => (2459, None), }; }; - let code = if self.merged_resolved_symbol(equals) != local { + let code = if !is_local(self, equals) { 2305 } else if files.options.module >= crate::resolve::ModuleKind::Es2015 { 2595 @@ -1065,10 +1091,9 @@ impl Checker<'_, '_> { { continue; } - // The key that identifies `this.name` or `this[key]` where the constructor assigns to - // it, and `getTypeOfSymbol` of the declaration: the declared type, with `this` - // uninstantiated. - let (key, ty) = match self.declared_member_name(file, member.key) { + // The name of the symbol, and `getTypeOfSymbol` of the declaration: the declared type, + // with `this` uninstantiated. + let (name, ty) = match self.declared_member_name(file, member.key) { Some(name) => { let sym = self.class_sym(file, c); let instance = self.declared_type(sym); @@ -1087,13 +1112,9 @@ impl Checker<'_, '_> { }; (Some(name), ty) } - None => { - // `[k]: T` is subject to the check whatever `k` is. - let PropKey::Computed(k) = member.key else { - continue; - }; - (self.access_key(file, k), None) - } + // `[k]: T` is subject to the check whatever `k` is. + None if matches!(member.key, PropKey::Computed(_)) => (None, None), + None => continue, }; let ty = match ty { Some(ty) => ty, @@ -1112,11 +1133,15 @@ impl Checker<'_, '_> { { continue; } - // `isPropertyInitializedInConstructor` - let is_assigned = match (constructor, key) { - (Some(func), Some(key)) => self.is_assigned_in_constructor(file, func, key, ty), - _ => false, - }; + // `isPropertyInitializedInConstructor`: the reference is `this.name`, or `this[k]` for + // the name `[k]`, whatever symbol that declares. + let is_assigned = constructor.is_some_and(|func| { + let key = match member.key { + PropKey::Computed(k) => self.access_key(file, k), + _ => name.map(super::flow::AccessKey::Name), + }; + key.is_some_and(|key| self.is_assigned_in_constructor(file, func, key, ty)) + }); if !is_assigned { // `DeclarationNameToString` let (start, end) = (member.name_pos, self.end_of_member_name(file, m)); @@ -1250,7 +1275,7 @@ impl Checker<'_, '_> { /// /// Only for the file being checked. No other task stores the entry of an unresolved identifier (`is_noted_for_check_file`), so /// `check_file` of another file evaluates its own identifiers itself, before its last call of this function. - fn report_unresolved_identifiers(&mut self) { + pub(super) fn report_unresolved_identifiers(&mut self) { while !self.unresolved_identifiers.is_empty() { let mut unresolved = std::mem::take(&mut self.unresolved_identifiers); unresolved.retain(|u| Some(u.0) == self.task.file); @@ -1332,9 +1357,19 @@ impl Checker<'_, '_> { Ok(_) => { let message = self.get_cannot_find_name_diagnostic_for_name(file, location, name); let meaning = SymFlags::VALUE | SymFlags::EXPORT_VALUE; - self.on_failed_to_resolve_symbol( - file, location, None, scope, name, meaning, message, - ); + // `getTargetOfAliasLikeExpression` has `checkExpressionCached` run while aliases + // are in progress, and a second time if that interrupts the first. + let lookups = self.files().failed_lookups_of(file, e); + let runs = lookups.iter().map(|it| it.aliases_in_progress); + for in_progress in runs.chain(lookups.is_empty().then_some(&[][..])) { + let outer = self.alias_targets_in_progress.len(); + self.alias_targets_in_progress + .extend_from_slice(in_progress); + self.on_failed_to_resolve_symbol( + file, location, None, scope, name, meaning, message, + ); + self.alias_targets_in_progress.truncate(outer); + } } } } @@ -1385,7 +1420,6 @@ impl Checker<'_, '_> { || options.verbatim_module_syntax || !matches!(hir.kind, FileKind::Ts | FileKind::Tsx) || hir.is_js - || module.is_lib || module.is_from_external_library) } @@ -1573,10 +1607,14 @@ impl Checker<'_, '_> { return; } // `result == nil` - if self - .files() - .resolve_name(file, scope, name, meaning) - .is_none() + let is_arguments_symbol = name == known::arguments + && meaning.intersects(SymFlags::VARIABLE) + && (self.bound(file)).is_in_function_with_arguments(self.hir(file), scope); + if !is_arguments_symbol + && self + .files() + .resolve_name(file, scope, name, meaning) + .is_none() && self.check_and_report_error_for_missing_prefix(file, location, name) { return; @@ -1766,11 +1804,18 @@ impl Checker<'_, '_> { } } // `checkAndReportErrorForUsingValueAsType` - if meaning.intersects(SymFlags::TYPE.difference(SymFlags::NAMESPACE)) - && let Some(symbol) = resolve_name(SymFlags::VALUE.difference(SymFlags::TYPE)) - { - let flags = self.get_symbol_flags(symbol); - if flags != SymFlags::all() && !flags.intersects(SymFlags::NAMESPACE) { + if meaning.intersects(SymFlags::TYPE.difference(SymFlags::NAMESPACE)) { + // `argumentsSymbol`, which is in no table, is a property. + let flags = if name == known::arguments + && (self.bound(file)).is_in_function_with_arguments(hir, scope) + { + Some(SymFlags::PROPERTY) + } else { + resolve_name(SymFlags::VALUE.difference(SymFlags::TYPE)) + .map(|symbol| self.get_symbol_flags(symbol)) + }; + if flags.is_some_and(|it| it != SymFlags::all() && !it.intersects(SymFlags::NAMESPACE)) + { self.error_at(at, 2749, &[reported]); return; } @@ -2039,7 +2084,7 @@ bun_core::comptime_string_map! { /// Whether `GetSpellingSuggestion` would suggest `candidate` for `name` if it were the only /// candidate. -pub(super) fn is_close(name: &[u8], candidate: &[u8]) -> bool { +pub(crate) fn is_close(name: &[u8], candidate: &[u8]) -> bool { let only = std::iter::once(candidate); get_spelling_suggestion(name, only, get_candidate_name, |a, b| a.cmp(b)).is_some() } @@ -2108,12 +2153,14 @@ fn similar_in_scope_and_where( let files = c.files(); let name = (name, c.atoms().bytes(name)); let among_globals = std::mem::take(&mut c.suggestions_among_globals); + // `try_resolve_alias` finds nothing for an alias in progress. + let is_function_of_candidate = c.alias_targets_in_progress.is_empty(); let suggested = files.suggested_symbol_for_nonexistent_symbol( location, name, meaning, c, - Some(&among_globals), + is_function_of_candidate.then_some(&among_globals), ); c.suggestions_among_globals = among_globals; // `Resolve` returns nil where the name may not be used. @@ -2136,9 +2183,13 @@ impl SuggestionLookup for Checker<'_, '_> { fn try_resolve_alias(&mut self, candidate: Sym) -> Option { let files = self.files(); + // `findResolutionCycleStartIndex(symbol, TypeSystemPropertyNameAliasTarget) >= 0` + if self.alias_targets_in_progress.contains(&candidate) { + return None; + } // As for `get_symbol_flags`: the symbol tables have the target, unless types are needed. if let Some(target) = files.resolve_alias(candidate) - && files.combined_symbol(candidate).is_none() + && !files.has_symbol_to_combine(candidate) { return Some(files.flags(target)); } @@ -2352,7 +2403,7 @@ fn entity_name_text(c: &Checker<'_, '_>, file: FileId, e: ExprId) -> Vec { } /// `TokenToString` of the operator of `a op b`, or of `a op= b`. -fn operator_text(op: BinOp, is_assignment: bool) -> Vec { +pub(super) fn operator_text(op: BinOp, is_assignment: bool) -> Vec { let text: &[u8] = match op { BinOp::Add => b"+", BinOp::Sub => b"-", @@ -2430,7 +2481,7 @@ pub(super) fn can_be_equal(c: &mut Checker<'_, '_>, left: TypeId, right: TypeId) impl Checker<'_, '_> { /// `isGlobalNaN` - fn is_global_nan(&self, file: FileId, e: ExprId) -> bool { + fn is_global_nan(&mut self, file: FileId, e: ExprId) -> bool { let ExprKind::Ident(name) = self.hir(file)[e].kind else { return false; }; @@ -2470,6 +2521,7 @@ impl Checker<'_, '_> { // value. A name that none of them declares is reported as missing on the type of the // right operand as it is. ExprKind::PrivateIdentifier(name) if !is_parenthesized(hir, left) => { + self.note_external_emit_helpers_check(file, left); if !self.bound(file).private_class.contains_key(&left) && !self.enclosing_classes(file, left).is_empty() { diff --git a/src/sema/check/errors_access.rs b/src/sema/check/errors_access.rs index 46ca8269b3df..ef20b7799396 100644 --- a/src/sema/check/errors_access.rs +++ b/src/sema/check/errors_access.rs @@ -219,11 +219,15 @@ impl<'p> Checker<'p, '_> { }); let members = (hir.members.iter().zip(bound.member_owner.iter())) .map(|(member, owner)| (member.name_pos, !matches!(owner, MemberOwner::None))); - // The name of `{ a }` is an expression, and `{ ...a }` has none. + // The name of `{ a }` is an expression, and `{ ...a }` has none. `parseIdentifierName` makes + // an `Identifier` of any token that names a `JsxAttribute` or an `ImportAttribute`. let properties = - (hir.props.iter().zip(bound.prop_owner.iter())).map(|(property, owner)| { + (hir.props.iter().zip(bound.prop_owner.iter())).map(|(property, &owner)| { let has_name = !matches!(property.kind, PropKind::Shorthand | PropKind::Spread); - (property.pos, has_name && owner.is_some()) + let is_in_object_literal = owner.is_some() + && matches!(hir[owner].kind, ExprKind::Object(_)) + && !hir.import_attributes.iter().any(|kept| kept.1 == owner); + (property.pos, has_name && is_in_object_literal) }); let elements = hir.pat_props.iter().map(|element| { let is_bound = !matches!(bound.pat_parent[element.value.idx()], PatParent::None); @@ -501,11 +505,7 @@ impl<'p> Checker<'p, '_> { let ExprKind::Ident(name) = hir[index].kind else { return false; }; - // `getResolvedSymbol` - let symbol = self - .symbol_of_identifier(file, index, name) - .and_then(|found| self.value_symbol_of_identifier(file, index, name, found)); - let Some(symbol) = symbol else { + let Some(symbol) = self.symbol_of_identifier(file, index, name) else { return false; }; if !self.files().flags(symbol).intersects(SymFlags::VARIABLE) { @@ -549,9 +549,7 @@ impl<'p> Checker<'p, '_> { let ExprKind::Ident(name) = hir[e].kind else { return None; }; - // `getResolvedSymbol` self.symbol_of_identifier(file, e, name) - .and_then(|found| self.value_symbol_of_identifier(file, e, name, found)) } _ => None, } @@ -720,8 +718,17 @@ impl<'p> Checker<'p, '_> { file: FileId, written: PropId, ) -> u32 { + let hir = self.hir(file); + // `bindThisPropertyAssignment`: `this.name = value` in a member of the literal declares `name` among its members. + if hir.is_js + && let Some(&(_, Decl::ThisProperty(first))) = self + .declarations_of_member(file, Decl::Property(written)) + .first() + { + return hir[first].pos; + } let first = self.first_declaration_of_literal_member(file, written); - self.hir(file)[first].pos + hir[first].pos } /// `declareSymbol`: the type parameters of a class or an interface are among its `members`, so @@ -842,9 +849,9 @@ impl<'p> Checker<'p, '_> { _ => None, }; let name = match bound.pat_parent[element.idx()] { - PatParent::Prop(_, p) if !hir[p].is_rest => self - .literal_type_from_property_name(file, hir[p].key, hir[p].name_kind) - .map(|key| (key, hir[p].pos)), + PatParent::Prop(_, p) if hir[p].key_pos != hir[element].pos => self + .literal_type_from_property_name(file, hir[p].key, hir[p].name_kind, hir[p].key_pos) + .map(|key| (key, hir[p].key_pos)), _ => own_name, }; let Some((expr_type, at_name)) = name else { @@ -1337,7 +1344,7 @@ impl<'p> Checker<'p, '_> { name_pos: u32, ) { let (at, writing) = (Parent::Expr(e), self.is_write_access(file, e)); - let error_node = |c: &Self| c.place_of_token(file, name_pos); + let error_node = |c: &Self| c.place_of_right(file, name, name_pos); self.check_property_accessibility_at_location( file, self.hir(file).node(e), diff --git a/src/sema/check/errors_aliases.rs b/src/sema/check/errors_aliases.rs index 6fb4aaaf749d..ce436b1ba3ea 100644 --- a/src/sema/check/errors_aliases.rs +++ b/src/sema/check/errors_aliases.rs @@ -14,13 +14,14 @@ //! `expected_errors` creates the TS2578 for each `@ts-expect-error`, and `Program::finish_file` //! drops those whose directive was used. +use super::errors_operators::language_version; use super::explain::NOWHERE; use super::sink::{NO_DIRECTIVE, held}; use super::*; use crate::bind::{ClassOwner, Decl, Parent, PatParent, SymbolId}; use crate::program::{TypeOnlyDeclaration, source_file_may_be_emitted}; use crate::resolve::{ - ModuleKind, Options, file_extension_is, get_relative_path_from_directory, + ModuleKind, Options, ScriptTarget, file_extension_is, get_relative_path_from_directory, has_ts_implementation_extension, is_declaration_file_name, join, path_is_relative, try_extract_ts_extension, }; @@ -230,7 +231,6 @@ impl Checker<'_, '_> { && !options.emit_declaration_only && matches!(hir.kind, FileKind::Ts | FileKind::Tsx) && !hir.is_js - && !module.is_lib && !module.is_from_external_library } @@ -343,16 +343,28 @@ impl Checker<'_, '_> { || options.verbatim_module_syntax || !matches!(hir.kind, FileKind::Ts | FileKind::Tsx) || hir.is_js - || module.is_lib || module.is_from_external_library { return; } let index = self.exprs_by_kind(file); + // `shouldTransformPrivateElementsOrClassStaticBlocks` + let transforms_private_elements = language_version(self) < ScriptTarget::ES2022; let mut accesses: Vec = [ExprTag::Dot, ExprTag::Index] .iter() .flat_map(|&tag| index.of(tag).iter().copied()) .filter(|&e| !bound.is_unchecked(e.idx()) && !bound.is_in_type_query(e)) + // `visitPropertyAccessExpression` of the class fields transformer, which comes earlier, + // has made `a.#b` a call of a helper. + .filter(|&e| match hir[e].kind { + ExprKind::Dot { name, .. } => { + !(transforms_private_elements + && self.is_private_name(name) + && (self.lookup_symbol_for_private_identifier_declaration(file, e, name)) + .is_some()) + } + _ => true, + }) .collect(); // Of two that start at the same position, the outer was created last. accesses.sort_by_key(|&e| (self.start_of(file, e), std::cmp::Reverse(e))); @@ -394,10 +406,17 @@ impl Checker<'_, '_> { let mut reported: Vec<(StmtId, Vec>)> = Vec::new(); let links = modules.iter().map(|&module| files.module_links(module)); for collision in links.flat_map(|links| links.export_collisions.iter()) { - let (of, first) = collision.first; - if collision.duplicate.0 == file - && let StmtKind::ExportStar { spec, .. } = self.hir(of)[first].kind + if collision.duplicate.0 != file { + continue; + } + // `extendExportSymbols` + if let Some((target, source)) = collision.symbols + && self.resolve_symbol(target) == self.resolve_symbol(source) { + continue; + } + let (of, first) = collision.first; + if let StmtKind::ExportStar { spec, .. } = self.hir(of)[first].kind { let specifier = self.aliases_specifier_text(of, self.hir(of)[first].start, spec); let arguments = vec![specifier, self.atom_text(collision.name)]; reported.push((collision.duplicate.1, arguments)); @@ -723,7 +742,7 @@ impl Checker<'_, '_> { } /// `checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol`: 1379 1380 - fn aliases_import_alias_of_type_only( + pub(super) fn aliases_import_alias_of_type_only( &mut self, file: FileId, x: ImportEqualsId, @@ -1390,7 +1409,9 @@ impl Checker<'_, '_> { ExprTag::NewTarget, ] { for &e in index.of(tag) { - self.aliases_import_call_or_meta_property(file, e); + if !self.is_never_checked(self.hir(file)[e].pos) { + self.aliases_import_call_or_meta_property(file, e); + } } } } diff --git a/src/sema/check/errors_assign.rs b/src/sema/check/errors_assign.rs index ea54a1431c89..30c7c5e93f4a 100644 --- a/src/sema/check/errors_assign.rs +++ b/src/sema/check/errors_assign.rs @@ -95,83 +95,127 @@ impl Checker<'_, '_> { let at = self.span_of_parenthesized_expr(file, e); self.check_initializer(file, e, target, at); } - let by_kind = self.exprs_by_kind(file); - self.check_assignments_among(file, by_kind.of(ExprTag::Assign), None); } - /// `checkAssignmentOperator` for those of `assignments` that are `target = value`: the - /// comparison. `check_plain_assignment` has the reference check. + /// `checkAssignmentOperator` for `assignment`, which is `target = value`: the comparison. + /// `check_plain_assignment` has the reference check. /// `right_type`: `checkExpression(right)`, where the caller has it. - pub(super) fn check_assignments_among( + pub(super) fn check_plain_assignment_operator( &mut self, file: FileId, - assignments: &[ExprId], + assignment: ExprId, right_type: Option, ) { let (hir, bound) = (self.hir(file), self.bound(file)); - for &assignment in assignments { - let i = assignment.idx(); - let ExprKind::Assign { - op: None, - target, - value, - } = hir.exprs[i].kind - else { - continue; - }; - if bound.is_unchecked(i) { - continue; - } - // `checkReferenceExpression`: only the invalid target is reported. - if super::errors_operators::why_no_reference(hir, target, 2364, 2779).is_some() { - continue; - } - // `[a = 1] = x`: a default, not an assignment. - if self.is_definite_assignment_target(file, ExprId(i as u32)) { - continue; - } - // `{ a = 1 }` that is not an assignment target (1312): `checkObjectLiteral` checks the - // initializer and not the name. - if matches!(bound.expr_parent[i], Parent::Prop(p) if hir[p].kind == PropKind::Shorthand) + let ExprKind::Assign { + op: None, + target, + value, + } = hir[assignment].kind + else { + return; + }; + if bound.is_unchecked(assignment.idx()) { + return; + } + // `checkReferenceExpression`: only the invalid target is reported. + if super::errors_operators::why_no_reference(hir, target, 2364, 2779).is_some() { + return; + } + if self.is_assignment_element_with_initializer(file, assignment) { + return; + } + // `{ a = 1 }` that is not an assignment target (1312): `checkObjectLiteral` checks the + // initializer and not the name. + let parent = bound.expr_parent[assignment.idx()]; + if matches!(parent, Parent::Prop(p) if hir[p].kind == PropKind::Shorthand) { + return; + } + // `checkExpression(left)`: an invalid assignment target has the error type, to which + // anything is assignable. + let left = self.type_of_expr(file, target); + if self.is_error_type(left) { + return; + } + let source = match right_type { + Some(right_type) => right_type, + None => self.type_of_expr(file, value), + }; + // `undefined` assigned to a CommonJS export with more than one declaration is not checked. + // The declarations counted are those of the symbol the left side resolves to. + if source.is_undefined() + && let crate::bind::JsDeclarationKind::ExportsProperty(name) = + crate::bind::assignment_declaration_kind(hir, assignment) + && let ExprKind::Dot { obj, .. } | ExprKind::Index { obj, .. } = hir[target].kind + { + let object = self.type_of_expr(file, obj); + let object = self.apparent_type(object); + if let Some((prop, _)) = self.prop_ref(object, name) + && let PropSource::Symbol(sym) = prop.source + && self.files().decls(sym).len() > 1 { - continue; + return; } - // `checkExpression(left)`: an invalid assignment target has the error type, to which - // anything is assignable. - let left = self.type_of_expr(file, target); - if self.is_error_type(left) { - continue; + } + let head = self.exact_optional_head_message(file, target, source); + self.check_assignable_with_end( + file, + source, + left, + self.start_of(file, target), + self.end_of_expr(file, target), + value, + head.unwrap_or(2322), + ); + } + + /// Whether `checkDestructuringAssignment` takes the assignment `e` for a target with a default, + /// as in `[a = 1] = x`: `e`, as written, is an element or the value of a property of an + /// assignment pattern. It is checked with the pattern. + pub(super) fn is_assignment_element_with_initializer(&self, file: FileId, e: ExprId) -> bool { + let (hir, bound) = (self.hir(file), self.bound(file)); + let mut node = e; + loop { + // Parenthesized, it is an expression like any other: `checkReferenceAssignment`. + if is_parenthesized(hir, node) { + return false; } - let source = match right_type { - Some(right_type) => right_type, - None => self.type_of_expr(file, value), - }; - // `checkAssignmentOperator`: `undefined` assigned to a CommonJS export with more than one declaration is not checked. The - // declarations counted are those of the symbol the left side resolves to. - if source.is_undefined() - && let crate::bind::JsDeclarationKind::ExportsProperty(name) = - crate::bind::assignment_declaration_kind(hir, ExprId(i as u32)) - && let ExprKind::Dot { obj, .. } | ExprKind::Index { obj, .. } = hir[target].kind - { - let object = self.type_of_expr(file, obj); - let object = self.apparent_type(object); - if let Some((prop, _)) = self.prop_ref(object, name) - && let PropSource::Symbol(sym) = prop.source - && self.files().decls(sym).len() > 1 + let is_pattern = node != e; + node = match bound.expr_parent[node.idx()] { + Parent::Expr(parent) if parent.is_some() => match hir[parent].kind { + ExprKind::Array(_) => parent, + ExprKind::Spread(_) if is_pattern => match bound.expr_parent[parent.idx()] { + Parent::Expr(array) + if array.is_some() && matches!(hir[array].kind, ExprKind::Array(_)) => + { + array + } + _ => return false, + }, + ExprKind::Assign { + op: None, target, .. + } if is_pattern => return target == node, + _ => return false, + }, + Parent::Prop(p) + if matches!( + hir[p].kind, + PropKind::Init | PropKind::Shorthand | PropKind::Spread + ) => { - continue; + let literal = bound.prop_owner[p.idx()]; + if literal.is_none() || !matches!(hir[literal].kind, ExprKind::Object(_)) { + return false; + } + literal } - } - let head = self.exact_optional_head_message(file, target, source); - self.check_assignable_with_end( - file, - source, - left, - self.start_of(file, target), - self.end_of_expr(file, target), - value, - head.unwrap_or(2322), - ); + // `checkForOfStatement` + Parent::Stmt(head) if is_pattern && head.is_some() => { + return matches!(bound.stmt_parent[head.idx()], Parent::Stmt(owner) if owner.is_some() + && matches!(hir[owner].kind, StmtKind::ForOf { left, .. } if left == head)); + } + _ => return false, + }; } } @@ -217,10 +261,7 @@ impl Checker<'_, '_> { if strict && Self::is_pattern_without_names(hir, decl.pat) { return; } - // `isInAmbientOrTypeNode`: the initializer of an ambient binding pattern is a grammar error and is not compared. - if decl.flags.contains(Flags::AMBIENT) - && matches!(hir[decl.pat].kind, PatKind::Object(_) | PatKind::Array(_)) - { + if self.is_binding_pattern_in_ambient_or_type_node(file, decl.pat) { return; } let target = self.type_of_pat(file, decl.pat); @@ -269,7 +310,9 @@ impl Checker<'_, '_> { { self.check_literals_expected_by_pattern(file, param.default); } - if strict && Self::is_pattern_without_names(hir, param.pat) { + if strict && Self::is_pattern_without_names(hir, param.pat) + || self.is_binding_pattern_in_ambient_or_type_node(file, param.pat) + { return; } let target = self.param_default_target(file, p); @@ -306,11 +349,7 @@ impl Checker<'_, '_> { } } let strict = self.p.files.options.strict_null_checks; - let is_ambient = self - .var_decl_of_pat(file, pat) - .is_some_and(|d| hir[d].flags.contains(Flags::AMBIENT)); - // `isInAmbientOrTypeNode`: the default of a nested binding pattern in an ambient declaration is not compared. - if is_ambient && matches!(hir[pat].kind, PatKind::Object(_) | PatKind::Array(_)) { + if self.is_binding_pattern_in_ambient_or_type_node(file, pat) { return; } if default.is_some() @@ -415,18 +454,16 @@ impl Checker<'_, '_> { declared }; } - // Resolving the parameter also resolves the enclosing call, whose signature `open_contextual_signature` reads. + // Resolving the parameter also resolves the enclosing call, which checks the function. let resolved = self.type_of_pat(file, param.pat); let func = bound.param_fn[p.idx()]; if !matches!(hir[param.pat].kind, PatKind::Object(_) | PatKind::Array(_)) { return resolved; } - // A binding pattern is compared with `getWidenedTypeForVariableLikeDeclaration`, not with the type of a symbol. - // `contextuallyCheckFunctionExpressionOrObjectLiteralMethod` checks the parameters the first time the function is checked, so - // `getContextuallyTypedParameterType` sees the callee's signature before its type arguments are inferred. The adjustments of - // `assignContextualParameterTypes` and `assignParameterType` only reach the symbol's type. + // A binding pattern is compared with `getWidenedTypeForVariableLikeDeclaration`, not with the type of a symbol. The + // adjustments of `assignContextualParameterTypes` and `assignParameterType` only reach the symbol's type. let index = (p.0 - hir[func].params.start) as usize; - let Some(ty) = self.contextual_param_type(file, func, index) else { + let (Some(ty), _) = self.contextual_param_type_at_check(file, func, index) else { return resolved; }; let ty = if is_optional { self.optional(ty) } else { ty }; @@ -475,7 +512,8 @@ impl Checker<'_, '_> { } // For a JSDoc type assertion the error node is the type node. let (at, end) = if hir.is_in_jsdoc(hir[ty].pos) { - (hir[ty].pos, self.end_of_type_node(file, ty)) + let start = start_of_type(hir, ty); + (start, self.end_of_type_node_from(file, ty, start)) } else { ( self.start_inside_parentheses(file, e), @@ -494,7 +532,7 @@ impl Checker<'_, '_> { for &assignment in by_kind.of(ExprTag::Assign) { let i = assignment.idx(); let ExprKind::Assign { - op: None, + op: None | Some(BinOp::And | BinOp::Or | BinOp::Nullish), target, value, } = hir.exprs[i].kind @@ -503,6 +541,7 @@ impl Checker<'_, '_> { }; if bound.is_unchecked(i) || !matches!(hir[target].kind, ExprKind::Object(_) | ExprKind::Array(_)) + || self.is_never_checked(hir.exprs[i].pos) { continue; } @@ -668,18 +707,6 @@ impl Checker<'_, '_> { } } - /// The variable declaration whose name is `pat` or contains `pat`. `None` for a parameter. - fn var_decl_of_pat(&self, file: FileId, mut pat: PatId) -> Option { - use crate::bind::PatParent; - loop { - match self.bound(file).pat_parent[pat.idx()] { - PatParent::Prop(outer, _) | PatParent::Elem(outer, _) => pat = outer, - PatParent::Var(d) => return Some(d), - PatParent::Param(_) | PatParent::None => return None, - } - } - } - /// FOR SPEED: `check_type_reference_or_import` has run for `node` since `check_file` began, has /// reported nothing, and has read nothing provisional. A type node in an expression is checked /// by `look_at_type_node` and again by the walk. @@ -837,7 +864,8 @@ impl Checker<'_, '_> { }; let keys = self.union(&[TypeId::STRING, TypeId::NUMBER, TypeId::SYMBOL]); if at.is_some() && !self.is_assignable(ty, keys) { - let error_node = (file, hir[at].pos, self.end_of_type_node(file, at)); + let start = start_of_type(hir, at); + let error_node = (file, start, self.end_of_type_node_from(file, at, start)); self.check_type_assignable_to(ty, keys, Some(error_node), None); } } @@ -1278,47 +1306,27 @@ impl Checker<'_, '_> { head_message: Option, mut diagnostic_output: Option<&mut Vec>, ) -> bool { - let relation = Relation::Assignable; - let is_related = self.try_is_type_related_to(source, target, relation, false); - match is_related { - Ok(true) => return true, - Ok(false) if error_node.is_none() => return false, - Ok(false) => { - let output = diagnostic_output.as_deref_mut(); - if let Some((file, e)) = expr - && self.elaborate_error( - file, - e, - is_effective, - source, - target, - head_message, - output, - ) - { - return false; - } - } - // The overflow is reported instead of the relation error. The pair is not compared again to elaborate. - Err(_) => {} + // An overflow of `isTypeRelatedTo` is a failure like any other. The run that has it reports + // it at `c.currentNode`. + if self.try_is_type_related_to(source, target, Relation::Assignable, false) == Ok(true) { + return true; + } + if error_node.is_none() { + return false; } let output = diagnostic_output.as_deref_mut(); - let is_assignable = - self.check_type_assignable_to_ex(source, target, error_node, head_message, output); - // `isTypeRelatedTo` already hit the overflow, with no node to report it on but - // `c.currentNode`: the assignment. - if let Err(code) = is_related - && let Some((file, e)) = expr - && let Parent::Expr(whole) = self.bound(file).expr_parent[e.idx()] - && whole.is_some() - && matches!(self.hir(file)[whole].kind, ExprKind::Assign { value, .. } if value == e) + if let Some((file, e)) = expr + && self.elaborate_error(file, e, is_effective, source, target, head_message, output) { - let start = self.start_inside_parentheses(file, whole); - let at = (file, start, self.end_inside_parentheses(file, whole)); - let diagnostic = self.new_diagnostic(at, code, &[Arg::Type(source), Arg::Type(target)]); - self.report_diagnostic(diagnostic, diagnostic_output); + return false; } - is_assignable + self.check_type_assignable_to_ex( + source, + target, + error_node, + head_message, + diagnostic_output, + ) } /// The diagnostics collected in a `diagnosticOutput`. @@ -1472,7 +1480,8 @@ impl Checker<'_, '_> { continue; } // `getLiteralTypeFromProperty(.., TypeFlagsStringOrNumberLiteralOrUnique)` - let name_type = self.literal_type_from_property_name(file, prop.key, prop.name_kind); + let (key, name_kind) = (prop.key, prop.name_kind); + let name_type = self.literal_type_from_property_name(file, key, name_kind, prop.pos); let Some(name_type) = name_type.filter(|&it| self.property_name_of_type(it).is_some()) else { continue; diff --git a/src/sema/check/errors_call.rs b/src/sema/check/errors_call.rs index b594b9a937f0..03e37e2833e9 100644 --- a/src/sema/check/errors_call.rs +++ b/src/sema/check/errors_call.rs @@ -49,6 +49,7 @@ impl Checker<'_, '_> { hir.exprs[i].kind, ExprKind::Call(_) | ExprKind::New(_) | ExprKind::TaggedTemplate(_) ) || bound.is_unchecked(i) + || self.is_never_checked(hir.exprs[i].pos) { continue; } @@ -122,6 +123,10 @@ impl Checker<'_, '_> { self.chain_receiver(file, data.callee, data.chain).0 }; let called = self.check_non_null_callee(file, data.callee, called, is_new); + // `silentNeverSignature` + if called == TypeId::SILENT_NEVER { + return; + } let apparent = self.apparent_type(called); // `resolveErrorCall` if self.is_error_type(apparent) { @@ -284,6 +289,14 @@ impl Checker<'_, '_> { self.invocation_error(at, 2351, data.callee, apparent, (true, false), None); } + /// `getResolvedSignature(node) == silentNeverSignature`, for the call or the `new` expression + /// `e`: `resolveCallExpression` and `resolveNewExpression` have returned before they check an + /// argument. + pub(super) fn is_silent_never_signature(&mut self, file: FileId, e: ExprId) -> bool { + let resolved = self.resolved_signature(file, e); + resolved.sig.is_none() && resolved.ret == TypeId::SILENT_NEVER + } + /// Error span of a callee: from the start of the (possibly parenthesized) expression to its error end. fn span_of_callee(&self, file: FileId, callee: ExprId) -> (FileId, u32, u32) { ( @@ -454,7 +467,11 @@ impl Checker<'_, '_> { } // `getOptionalCallSignature`: `void | undefined` after a `?.` that may short-circuit. let return_type = self.type_of_expr(file, e); - if self.flags(return_type) & tf::VOID == 0 || self.sig_predicate(sig).is_none() { + if self.flags(return_type) & tf::VOID == 0 + || self.sig_predicate(sig).is_none() + // The initializer of a `for` and the object of a `with` are stored as statements too. + || hir.kind(hir.parent(hir.node(e))) != Kind::ExpressionStatement + { return; } let start = self.start_of(file, data.callee); @@ -594,7 +611,10 @@ impl Checker<'_, '_> { PropSource::Symbol(sym) => { (self.flags_of_property(*sym)).contains(SymFlags::GET_ACCESSOR) } - PropSource::Literal(f, p) => self.hir(*f)[*p].kind == PropKind::Getter, + // `SymbolFlagsProperty|member.Flags` + PropSource::Literal(f, p) => { + (self.flags_of_literal_member(*f, *p)).contains(SymFlags::GET_ACCESSOR) + } // `propFlags` of `createUnionOrIntersectionProperty` PropSource::Intersected(..) => { prop.flags & (PropFlags::ACCESSOR | PropFlags::WRITE_ONLY) == PropFlags::ACCESSOR @@ -950,8 +970,7 @@ impl Checker<'_, '_> { return false; } } - // `getTypeAtPosition(signature, i)` for every argument. - let params = self.sig_params_up_to(sig, args.len()); + let mut params = self.sig_params(sig); let rest = self.non_array_rest_type(¶ms); let count = if rest.is_some() { (self.parameter_count(¶ms) - 1).min(args.len()) @@ -963,6 +982,11 @@ impl Checker<'_, '_> { if matches!(hir[node].kind, ExprKind::Missing) { continue; } + // `getTypeAtPosition(signature, i)`: a cycle through the type of a parameter is found + // here, and not for a parameter after the first argument that fails. + if let List::Own(_) = params { + params = self.sig_params_up_to(sig, i + 1); + } let Some(expected) = self.param_type_at(¶ms, i) else { continue; }; @@ -982,6 +1006,7 @@ impl Checker<'_, '_> { if self.related(actual, expected, relation) { continue; } + self.note_parameter_types_resolved(sig, ¶ms, i + 1); if report { let check_node = self.effective_check_node(file, node); let error_node = match decorator { @@ -1021,6 +1046,7 @@ impl Checker<'_, '_> { } return false; } + self.note_parameter_types_resolved(sig, ¶ms, args.len()); if let Some(rest) = rest { let actual = self.spread_argument_type(file, args, count, rest, None, check_mode); if !self.related(actual, rest, relation) { @@ -1265,7 +1291,7 @@ impl Checker<'_, '_> { /// `isPromiseResolveArityError`: the callee is the `resolve` of `new Promise((resolve) => /// ...)`. Not if `resolve`, the function or `Promise` is parenthesized: parentheses are nodes. - fn is_promise_resolve_arity_error(&self, file: FileId, e: ExprId, c: CallId) -> bool { + fn is_promise_resolve_arity_error(&mut self, file: FileId, e: ExprId, c: CallId) -> bool { let (hir, bound, files) = (self.hir(file), self.bound(file), self.files()); let callee = hir[c].callee; let ExprKind::Ident(name) = hir[callee].kind else { @@ -1375,7 +1401,7 @@ impl Checker<'_, '_> { } let end = self.end_of_type_argument_list(file, type_args); self.add_diagnostic(Reported::new( - (file, hir[first].pos, end), + (file, start_of_type(hir, first), end), code, held(counts), )); diff --git a/src/sema/check/errors_circular.rs b/src/sema/check/errors_circular.rs index 8e19d127c664..3540780330d9 100644 --- a/src/sema/check/errors_circular.rs +++ b/src/sema/check/errors_circular.rs @@ -1,75 +1,15 @@ -//! Circularity errors: 2313 2615, and 2502 2577 7022 7023 7024. +//! Circularity errors: 2313, and 2502 2577 7022 7023 7024. //! //! In TypeScript 7.0.2's checker.go these result from `pushTypeResolution` finding the requested //! resolution already in progress, in `getBaseConstructorTypeOfClass`, `getBaseTypes` and //! `getResolvedBaseConstraint`: every entry from there to the top of the stack is in the cycle, and -//! an entry that only leads to it is not. Here the cycles are detected in the syntax, and among -//! those that `Checker::enter` found when the types were requested. +//! an entry that only leads to it is not. Here they are the cycles that `Checker::enter` found when +//! the types were requested. use super::explain::NOWHERE; use super::sink::held; use super::*; use crate::bind::{Decl, FnOwner, MemberOwner, Parent, PatParent, Symbol, SymbolId}; -use smallvec::SmallVec; - -type TypeParams = SmallVec<[TypeParamId; 8]>; - -/// Whether `eagerly_resolved_mapped_keys` can find anything in `node`, regardless of the type -/// argument counts of the names in it. -fn contains_mapped_type_node(hir: &hir::File, node: TypeNodeId) -> bool { - if node.is_none() { - return false; - } - match hir[node].kind { - TypeNodeKind::Mapped(_) => true, - TypeNodeKind::Array(t) - | TypeNodeKind::Keyof(t) - | TypeNodeKind::Readonly(t) - | TypeNodeKind::JSDoc { ty: t, .. } => contains_mapped_type_node(hir, t), - TypeNodeKind::Tuple(elems) => elems - .iter() - .any(|e| contains_mapped_type_node(hir, hir[e].ty)), - TypeNodeKind::Ref { args: list, .. } - | TypeNodeKind::Union(list) - | TypeNodeKind::Intersection(list) - | TypeNodeKind::Template { types: list, .. } - | TypeNodeKind::Typeof { args: list, .. } => { - hir.ids(list).any(|t| contains_mapped_type_node(hir, t)) - } - TypeNodeKind::IndexedAccess { obj, index } => { - contains_mapped_type_node(hir, obj) || contains_mapped_type_node(hir, index) - } - TypeNodeKind::Cond { check, extends, .. } => { - contains_mapped_type_node(hir, check) || contains_mapped_type_node(hir, extends) - } - _ => false, - } -} - -/// `getUnionType`, `getIntersectionType`: the keyword that determines the type at `node` regardless -/// of its other members. In a union `any`, and then `unknown`, absorbs the rest. In an intersection -/// `never`, and then `any`. -fn absorbing_keyword(hir: &hir::File, node: TypeNodeId) -> Option { - let strongest = |members: IdList, first: Keyword, second: Keyword| { - let mut found = None; - for member in hir.ids(members) { - match absorbing_keyword(hir, member) { - Some(keyword) if keyword == first => return Some(first), - Some(keyword) if keyword == second => found = Some(second), - _ => {} - } - } - found - }; - match hir[node].kind { - TypeNodeKind::Keyword(keyword @ (Keyword::Any | Keyword::Unknown | Keyword::Never)) => { - Some(keyword) - } - TypeNodeKind::Union(members) => strongest(members, Keyword::Any, Keyword::Unknown), - TypeNodeKind::Intersection(members) => strongest(members, Keyword::Never, Keyword::Any), - _ => None, - } -} impl Checker<'_, '_> { pub(super) fn check_circularities(&mut self, file: FileId) { @@ -78,7 +18,7 @@ impl Checker<'_, '_> { let unchecked = self.unchecked_jsdoc_types(file); // `checkClassLikeDeclaration`, `checkInterfaceDeclaration` for c in 0..hir.classes.len() { - if bound.class_symbol[c].is_some() { + if bound.class_symbol[c].is_some() && !self.is_never_checked(hir.classes[c].start) { let own = self.class_sym(file, ClassId(c as u32)); self.base_constructor_type_of_class(own); self.base_types(own); @@ -88,29 +28,29 @@ impl Checker<'_, '_> { let own = self.files().sym(file, symbol); self.base_types(own); } - self.check_circular_mapped_properties(); for p in 0..hir.type_params.len() { let constraint = hir.type_params[p].constraint; if constraint.is_none() || bound.type_param_scope[p].is_none() + || bound.type_param_symbol[p].is_none() || unchecked.contain(hir[constraint].pos) { continue; } let own = TypeParamId(p as u32); - let mut is_circular = self.is_constraint_circular(file, own); - // `checkTypeParameter`: the base constraint is requested, which detects the cycles that - // are not visible in the syntax: through the target of a type alias, through `T[K]`, - // through a conditional type. - if !is_circular && bound.type_param_symbol[p].is_some() { - let param = self.type_param(file, own); - is_circular = !self.has_non_circular_base_constraint(param); + // `getConstraintDeclaration`: the declarations of a class or an interface declare one + // type parameter. + let (of, declaration, _) = + self.type_param_declaration_with(file, own, |it: &TypeParam| it.constraint); + if (of, declaration) != (file, own) { + continue; } - if is_circular { + let param = self.type_param(file, own); + if !self.has_non_circular_base_constraint(param) { let start = start_of_type(hir, constraint); let end = self.end_of_type_node_from(file, constraint, start); let name = self.atom_text(hir.type_params[p].name); - let related = self.origin_of_circular_constraint(file, own, start, end); + let related = self.origin_of_circular_constraint(param, file, constraint); self.error_at((file, start, end), 2313, &[Arg::Bytes(&name)]) .related_information .extend(related); @@ -118,15 +58,9 @@ impl Checker<'_, '_> { } } - /// `getResolvedBaseConstraint`: 2313 for the key of the mapped type at `mapped`, which had to - /// be resolved to decide whether `extending` can extend the type. `c.currentNode` is - /// `extending`, which is being checked. - pub(super) fn report_circular_mapped_key( - &mut self, - file: FileId, - mapped: TypeNodeId, - extending: (FileId, Decl), - ) { + /// `getResolvedBaseConstraint`: 2313 for the key of the mapped type at `mapped`. A cycle has + /// closed around the resolution of its base constraint. + pub(super) fn report_circular_mapped_key(&mut self, file: FileId, mapped: TypeNodeId) { let hir = self.hir(file); let TypeNodeKind::Mapped(m) = hir[mapped].kind else { return; @@ -136,24 +70,24 @@ impl Checker<'_, '_> { // order. Diagnostics that the check of a later file adds to it are never read. let files = self.files(); let order = |f: FileId| (!files.module(f).is_lib, files.rank_of_file(f)); - if param.constraint.is_none() || order(extending.0) > order(file) { + let is_read = (self.task.file).is_none_or(|checked| order(checked) <= order(file)); + let constraint = param.constraint; + if constraint.is_none() || !is_read { return; } - let start = start_of_type(hir, param.constraint); - let end = self.end_of_type_node_from(file, param.constraint, start); + let start = start_of_type(hir, constraint); + let end = self.end_of_type_node_from(file, constraint, start); let mut err = self.new_diagnostic((file, start, end), 2313, &[Arg::Atom(param.name)]); - if let (of, Decl::Interface(i)) = extending { - // `isNodeDescendantOf` - let is_written_in_it = of == file - && (hir[hir[i].stmt].start..self.end_of_stmt(file, hir[i].stmt)) - .contains(&hir[mapped].pos); - if !is_written_in_it { - let at = self.place_of_token(of, self.hir(of)[i].name_pos); - let origin = self.new_diagnostic(at, 2751, &[]); - err.add_related_info(origin); - } + let key = self.type_param(file, hir[m].param); + if !(self.circular_constraint_origins.iter()).any(|it| it.0 == key) { + let current = self.current_node().or(self.current_source_element); + let current = current.filter(|_| self.eager.is_empty()); + self.circular_constraint_origins.push((key, current)); + } + if let Some(origin) = self.origin_of_circular_constraint(key, file, constraint) { + err.add_related_info(origin); } - self.add_diagnostic(err); + self.add_diagnostic_of(Some(Query::TypeNode(file, constraint)), err); } /// Requests the types for which `reportCircularityError`, `getReturnTypeOfSignature` and @@ -166,6 +100,7 @@ impl Checker<'_, '_> { if !matches!(hir[pat].kind, PatKind::Ident(_)) || matches!(bound.pat_parent[i], PatParent::None) || unchecked.contain(hir[pat].pos) + || self.is_never_checked(hir[pat].pos) || self.returns_before_type_of_symbol(file, pat) { continue; @@ -187,6 +122,7 @@ impl Checker<'_, '_> { MemberKind::Property | MemberKind::Getter | MemberKind::Setter ) || matches!(bound.member_owner[i], MemberOwner::None) || unchecked.contain(hir[member].start) + || self.is_never_checked(hir[member].start) { continue; } @@ -202,7 +138,10 @@ impl Checker<'_, '_> { } for i in 0..hir.fns.len() { let func = FnId(i as u32); - if matches!(bound.fns[i].owner, FnOwner::None) || unchecked.contain(hir[func].start) { + if matches!(bound.fns[i].owner, FnOwner::None) + || unchecked.contain(hir[func].start) + || self.is_never_checked(hir[func].start) + { continue; } // An annotated accessor of a class, an interface or a type literal was already @@ -210,16 +149,10 @@ impl Checker<'_, '_> { let is_member = matches!(hir[func].kind, FnKind::Getter | FnKind::Setter) && !(hir[func].kind == FnKind::Getter && matches!(bound.fns[i].owner, FnOwner::Expr(_))); - // `checkFunctionOrMethodDeclaration` requests the inferred return type of a generator only, - // `checkReturnStatement` that of the function it is in. - let is_requested = !matches!(hir[func].kind, FnKind::Decl | FnKind::Method) - || matches!(bound.fns[i].owner, FnOwner::Expr(_)) - || hir[func].flags.contains(Flags::GENERATOR) - || !bound.fns[i].returns.is_empty(); if hir[func].ret.is_some() && !is_member || hir[func].ret.is_none() && !matches!(hir[func].body, FnBody::None) - && is_requested + && self.is_inferred_return_type_requested(file, func) { self.return_type_of_fn(file, func); } @@ -228,6 +161,22 @@ impl Checker<'_, '_> { self.check_circular_assignment_declarations(file); } + /// Whether the check of the declaration `func` requests its inferred return type. + /// `checkFunctionOrMethodDeclaration` requests that of a generator only, + /// `checkAccessorDeclaration` none for a setter, `checkReturnStatement` that of the function it + /// is in. + pub(super) fn is_inferred_return_type_requested(&self, file: FileId, func: FnId) -> bool { + let (hir, info) = (self.hir(file), &self.bound(file).fns[func.idx()]); + let is_requested_at_declaration = match hir[func].kind { + FnKind::Setter => false, + FnKind::Decl | FnKind::Method => { + matches!(info.owner, FnOwner::Expr(_)) || hir[func].flags.contains(Flags::GENERATOR) + } + _ => true, + }; + is_requested_at_declaration || !info.returns.is_empty() + } + /// The end of `getTypeOfAccessors`, where `popTypeResolution` finds the cycle. `members`: the declarations of the property `sym`. pub(super) fn report_circular_accessors(&mut self, sym: Sym, members: &[(FileId, MemberId)]) { let of_kind = |c: &Self, kind: MemberKind| { @@ -326,42 +275,6 @@ impl Checker<'_, '_> { } } - /// `getTypeOfMappedSymbol`: 2615 at `c.currentNode`, the type node being checked when the type of a property of a mapped type - /// turns out to depend on itself. For the cycles that this task has found since the last call, in whatever file the node is. - /// A task that hits the entry of the property has nothing to report. - pub(super) fn check_circular_mapped_properties(&mut self) { - let mut found = std::mem::take(&mut self.circular_mapped_props); - // The first cycle found at a node names the property. - found.sort_by_key(|&(node, ..)| node); - found.dedup_by_key(|&mut (node, ..)| node); - for ((file, node), mapped, name) in found { - // A variable of that type that is read during emit creates the type first. - let created = self.type_from_node(file, node); - // Under any alias: the keys of the mapped type, which lead into the cycle, are the same. - let created = self.intern(self.data(created).clone_in(self.arena)); - let variable = if matches!(self.data(created), TypeData::Anon { .. }) { - self.first_variable_read_by_emit(file, |c, ty| { - c.intern(c.data(ty).clone_in(self.arena)) == created - }) - } else { - None - }; - let (start, end) = match variable { - Some(at) => (at, self.end_of_token_at(file, at)), - None => (self.hir(file)[node].pos, self.end_of_type_node(file, node)), - }; - let args = vec![ - match self.prop_ref(mapped, name) { - Some((prop, _)) => self.prop_to_string(prop), - None => self.atom_text(name), - }, - self.type_to_string(mapped), - ]; - let err = Reported::new((file, start, end), 2615, held(args)); - self.add_diagnostic_of(Some(Query::MappedProp(mapped, name)), err); - } - } - /// `getNameOfDeclaration`: the position of the name of `func`: its own or, for an anonymous /// function expression, the name it is assigned to (`GetAssignedName`). fn name_of_function(&self, file: FileId, func: FnId) -> Option { @@ -398,10 +311,12 @@ impl Checker<'_, '_> { let (hir, bound) = (self.hir(file), self.bound(file)); let no_implicit_any = self.p.files.options.no_implicit_any; let fn_owner = bound.fns[func.idx()].owner; - let named = |c: &mut Self, of: FnId, code: u32| { + // `printed`: the position of the name in the message, if it is not that of `of`. + let named = |c: &mut Self, of: FnId, code: u32, printed: Option| { if let Some(start) = c.name_of_function(file, of) { let end = c.end_of_name_at(file, start); - let name = c.source_text(file, start, end); + let printed = printed.unwrap_or(start); + let name = c.source_text(file, printed, c.end_of_name_at(file, printed)); let err = c.new_diagnostic((file, start, end), code, &[Arg::Bytes(&name)]); c.add_diagnostic_of(owner, err); return true; @@ -411,7 +326,15 @@ impl Checker<'_, '_> { if matches!(hir[func].kind, FnKind::Getter | FnKind::Setter) { // The accessors of classes, interfaces and type literals are reported with the property // they declare. - if matches!(fn_owner, FnOwner::Expr(_)) { + if let FnOwner::Expr(e) = fn_owner { + // `symbolToString`: the name of the first declaration of the symbol. + let symbol = match bound.expr_parent[e.idx()] { + Parent::Prop(p) => { + let first = self.first_declaration_of_literal_member(file, p); + Some(hir[first].pos) + } + _ => None, + }; let getter = (hir[func].kind == FnKind::Getter).then_some(func); let setter = match getter { Some(getter) => (self.sibling_accessor(file, getter, FnKind::Setter)) @@ -423,20 +346,23 @@ impl Checker<'_, '_> { node.is_some() }); match (getter, setter) { - (Some(getter), _) if hir[getter].ret.is_some() => named(self, getter, 2502), - (_, Some(setter)) => named(self, setter, 2502), - (Some(getter), None) => no_implicit_any && named(self, getter, 7023), + (Some(getter), _) if hir[getter].ret.is_some() => { + named(self, getter, 2502, symbol) + } + (_, Some(setter)) => named(self, setter, 2502, symbol), + (Some(getter), None) => no_implicit_any && named(self, getter, 7023, symbol), (None, None) => false, }; } } else if hir[func].ret.is_some() { let ret = hir[func].ret; - let at = (file, hir[ret].pos, self.end_of_type_node(file, ret)); + let start = start_of_type(hir, ret); + let at = (file, start, self.end_of_type_node_from(file, ret, start)); let err = self.new_diagnostic(at, 2577, &[]); self.add_diagnostic_of(owner, err); } else if no_implicit_any && !matches!(hir[func].body, FnBody::None) - && !named(self, func, 7023) + && !named(self, func, 7023, None) { let (start, end) = self.error_range_of_fn(file, func); let err = self.new_diagnostic((file, start, end), 7024, &[]); @@ -444,320 +370,25 @@ impl Checker<'_, '_> { } } - /// A file is emitted before it is checked: `markPropertyAliasReferenced` resolves the type of - /// the `a` of every `a.b`, then `GetConstantValue` that of every `a.b` and `a[b]`. Returns the - /// position of the first `a`, in that order, that is an identifier and whose type satisfies - /// `is_it`. - fn first_variable_read_by_emit( - &mut self, - file: FileId, - mut is_it: impl FnMut(&mut Self, TypeId) -> bool, - ) -> Option { - let (hir, bound) = (self.hir(file), self.bound(file)); - let options = &self.p.files.options; - if options.no_emit || options.isolated_modules || hir.kind == FileKind::Declaration { - return None; - } - let index = self.exprs_by_kind(file); - // Whether it is only visited in the second pass, and its position. - let mut first: Option<(bool, u32)> = None; - for (tag, is_second) in [(ExprTag::Dot, hir.is_js), (ExprTag::Index, true)] { - for &e in index.of(tag) { - let (ExprKind::Dot { obj, .. } | ExprKind::Index { obj, .. }) = hir[e].kind else { - continue; - }; - let at = (is_second, hir[obj].pos); - if !matches!(hir[obj].kind, ExprKind::Ident(_)) - || bound.is_unchecked(e.idx()) - || bound.is_in_type_query(e) - || first.is_some_and(|first| first <= at) - { - continue; - } - let ty = self.type_of_expr(file, obj); - if is_it(self, ty) { - first = Some(at); - } - } - } - first.map(|first| first.1) - } - - /// `getResolvedBaseConstraint`: `c.currentNode` when the cycle that contains the type parameter - /// `own` is first detected, unless that node is inside the constraint of `own`, which spans - /// `start` to `end`, or encloses it. + /// `getResolvedBaseConstraint`: 2751 at `c.currentNode` when the constraint of `param` was found + /// to be circular, unless that node is in `error_node`, the constraint, or around it. fn origin_of_circular_constraint( - &mut self, - file: FileId, - own: TypeParamId, - start: u32, - end: u32, - ) -> Vec { - // `getNarrowableTypeForReference` requests the constraint of the type of a variable. - let variable = self.first_variable_read_by_emit(file, |c, ty| { - matches!( - *c.data(ty), - TypeData::TypeParam(of, declared, around) - if of == file - && around == MapperId::IDENTITY - && c.constraint_leads_to(file, declared, own) - ) - }); - let at = match variable { - Some(at) => Some(self.place_of_token(file, at)), - None => self - .first_reference_resolving_mapped_key(file, own) - .map(|node| { - let from = self.hir(file)[node].pos; - (file, from, self.end_of_type_node(file, node)) - }) - .filter(|&(_, from, to)| { - !(start..end).contains(&from) && !(from..to).contains(&start) - }), - }; - at.map(|at| Reported::bare(at, 2751)).into_iter().collect() - } - - /// Whether `from` is `to`, or its constraint leads to it, based on the syntax as in - /// `is_constraint_circular`. - fn constraint_leads_to(&self, file: FileId, from: TypeParamId, to: TypeParamId) -> bool { - let hir = self.hir(file); - let (mut seen, mut todo) = (TypeParams::new(), TypeParams::new()); - todo.push(from); - while let Some(next) = todo.pop() { - if next == to { - return true; - } - if !seen.contains(&next) { - seen.push(next); - if hir[next].constraint.is_some() { - self.type_parameters_of_constraint(file, hir[next].constraint, &mut todo); - } - } - } - false - } - - /// `getTypeFromMappedTypeNode` resolves the constraint of its key eagerly when the type is - /// created. For `own`, the key of a mapped type inside a type alias, that is when the first - /// type reference that leads to the alias is checked. Children have lower ids and are checked - /// first. - fn first_reference_resolving_mapped_key( &self, + param: TypeId, file: FileId, - own: TypeParamId, - ) -> Option { - let (hir, bound) = (self.hir(file), self.bound(file)); - if !hir.mapped.iter().any(|m| m.param == own) { - return None; - } - let written = hir[hir[own].constraint].pos; - let around = hir.aliases.iter().position(|alias| { - alias.ty.is_some() - && (hir[alias.ty].pos..self.end_of_type_node(file, alias.ty)).contains(&written) - })?; - if bound.alias_symbol[around].is_none() { - return None; - } - let alias = self.files().sym(file, bound.alias_symbol[around]); - (0..hir.types.len() as u32).map(TypeNodeId).find(|&node| { - self.alias_referred_to(file, node) - .is_some_and(|named| self.alias_leads_to(named, alias, &mut Vec::new())) - }) - } - - /// The type alias the type reference `node` names. - fn alias_referred_to(&self, file: FileId, node: TypeNodeId) -> Option { - let (hir, files) = (self.hir(file), self.files()); - let scope = self.bound(file).type_scope[node.idx()]; - let TypeNodeKind::Ref { name, .. } = hir[node].kind else { - return None; - }; - if scope.is_none() { - return None; - } - let names: SmallVec<[Atom; 4]> = hir.texts(name).collect(); - let named = files - .resolve_entity(file, scope, &names, SymFlags::TYPE) - .and_then(|s| files.resolve_alias_as(s, SymFlags::TYPE))?; - files - .flags(named) - .contains(SymFlags::TYPE_ALIAS) - .then_some(named) - } - - /// Whether creating the type aliased by `from` creates the type aliased by `to`. - fn alias_leads_to(&self, from: Sym, to: Sym, seen: &mut Vec) -> bool { - if from == to { - return true; - } - if seen.contains(&from) { - return false; - } - seen.push(from); - let mut named = Vec::new(); - for &(file, decl) in self.files().decls_of(from).iter() { - if let Decl::Alias(a) = decl { - self.eagerly_resolved_aliases(file, self.hir(file)[a].ty, &mut named); - } - } - named - .into_iter() - .any(|next| self.alias_leads_to(next, to, seen)) - } - - /// The type aliases referenced in the parts that are resolved eagerly when the type at `node` - /// is created, as in `eagerly_resolved_mapped_keys`: for a mapped type the constraint of its - /// key. - fn eagerly_resolved_aliases(&self, file: FileId, node: TypeNodeId, into: &mut Vec) { - if node.is_none() { - return; - } + error_node: TypeNodeId, + ) -> Option { + let mut origins = self.circular_constraint_origins.iter(); + let current = origins.find(|it| it.0 == param)?.1?; + let (of, current_node) = self.node_of_current_node(current); let hir = self.hir(file); - match hir[node].kind { - TypeNodeKind::Mapped(m) => { - self.eagerly_resolved_aliases(file, hir[hir[m].param].constraint, into) - } - TypeNodeKind::Array(t) - | TypeNodeKind::Keyof(t) - | TypeNodeKind::Readonly(t) - | TypeNodeKind::JSDoc { ty: t, .. } => self.eagerly_resolved_aliases(file, t, into), - TypeNodeKind::Tuple(elems) => { - for e in elems.iter() { - self.eagerly_resolved_aliases(file, hir[e].ty, into); - } - } - TypeNodeKind::Ref { args, .. } => { - into.extend(self.alias_referred_to(file, node)); - for t in hir.ids(args) { - self.eagerly_resolved_aliases(file, t, into); - } - } - TypeNodeKind::Union(list) - | TypeNodeKind::Intersection(list) - | TypeNodeKind::Template { types: list, .. } => { - for t in hir.ids(list) { - self.eagerly_resolved_aliases(file, t, into); - } - } - TypeNodeKind::IndexedAccess { obj, index } => { - self.eagerly_resolved_aliases(file, obj, into); - self.eagerly_resolved_aliases(file, index, into); - } - TypeNodeKind::Cond { check, extends, .. } => { - self.eagerly_resolved_aliases(file, check, into); - self.eagerly_resolved_aliases(file, extends, into); - } - _ => {} - } - } - - /// `hasNonCircularBaseConstraint`, negated and based on the syntax: whether the constraint of - /// the type parameter `own` leads back to it, through the type parameters - /// `type_parameters_of_constraint` finds in each constraint. One that only leads to a cycle is - /// not in it. - pub(super) fn is_constraint_circular(&self, file: FileId, own: TypeParamId) -> bool { - let constraint = self.hir(file)[own].constraint; - if constraint.is_none() { - return false; - } - let mut mentioned = TypeParams::new(); - self.type_parameters_of_constraint(file, constraint, &mut mentioned); - (mentioned.iter()).any(|&from| self.constraint_leads_to(file, from, own)) - } - - /// The type parameters a constraint reduces to: itself, the members of a union or an - /// intersection, and the keys of the mapped types that are created with it. - fn type_parameters_of_constraint(&self, file: FileId, node: TypeNodeId, into: &mut TypeParams) { - let (hir, bound) = (self.hir(file), self.bound(file)); - match hir[node].kind { - TypeNodeKind::Ref { name, args } if args.is_empty() && name.len() == 1 => { - let found = self.files().resolve_name( - file, - bound.type_scope[node.idx()], - hir[name.at(0)].text, - SymFlags::TYPE, - ); - if let Some(found) = found - && found.file == file - && let Some(&Decl::TypeParam(p)) = self.files().symbol(found).decls.first() - { - into.push(p); - } - } - // `computeBaseConstraint` uses the type: `T | unknown` and `T & never` no longer - // contain `T`. - TypeNodeKind::Union(types) | TypeNodeKind::Intersection(types) - if absorbing_keyword(hir, node).is_none() => - { - for t in hir.ids(types) { - self.type_parameters_of_constraint(file, t, into); - } - } - _ => self.eagerly_resolved_mapped_keys(file, node, into), - } - } - - /// `getTypeFromMappedTypeNode` resolves the constraint of its key eagerly when the type is - /// created: the keys of the mapped types that are created together with `node`, which is in a - /// constraint, where nothing is deferred (`isDeferredTypeReferenceNode`). Members, signatures, - /// the templates of mapped types and their name types are resolved lazily. - fn eagerly_resolved_mapped_keys(&self, file: FileId, node: TypeNodeId, into: &mut TypeParams) { - if node.is_none() { - return; - } - let (hir, bound) = (self.hir(file), self.bound(file)); - match hir[node].kind { - TypeNodeKind::Mapped(m) => into.push(hir[m].param), - TypeNodeKind::Array(t) - | TypeNodeKind::Keyof(t) - | TypeNodeKind::Readonly(t) - | TypeNodeKind::JSDoc { ty: t, .. } => self.eagerly_resolved_mapped_keys(file, t, into), - TypeNodeKind::Tuple(elems) => { - for e in elems.iter() { - self.eagerly_resolved_mapped_keys(file, hir[e].ty, into); - } - } - TypeNodeKind::Ref { name, args } => { - if !hir.ids(args).any(|t| contains_mapped_type_node(hir, t)) { - return; - } - // `getTypeFromClassOrInterfaceReference`, `getTypeFromTypeAliasReference`: a wrong - // number of type arguments is an error, and they are not resolved. Those of an - // unresolved name are. - let files = self.files(); - let names: SmallVec<[Atom; 4]> = hir.texts(name).collect(); - let named = files - .resolve_entity(file, bound.type_scope[node.idx()], &names, SymFlags::TYPE) - .and_then(|s| files.resolve_alias_as(s, SymFlags::TYPE)); - if let Some(named) = named { - let (least, most) = self.type_argument_arity(named); - if !(least..=most).contains(&args.len()) { - return; - } - } - for t in hir.ids(args) { - self.eagerly_resolved_mapped_keys(file, t, into); - } - } - TypeNodeKind::Union(list) - | TypeNodeKind::Intersection(list) - | TypeNodeKind::Template { types: list, .. } - | TypeNodeKind::Typeof { args: list, .. } => { - for t in hir.ids(list) { - self.eagerly_resolved_mapped_keys(file, t, into); - } - } - TypeNodeKind::IndexedAccess { obj, index } => { - self.eagerly_resolved_mapped_keys(file, obj, into); - self.eagerly_resolved_mapped_keys(file, index, into); - } - // Which branch is taken, if any, cannot be determined from the syntax. - TypeNodeKind::Cond { check, extends, .. } => { - self.eagerly_resolved_mapped_keys(file, check, into); - self.eagerly_resolved_mapped_keys(file, extends, into); - } - _ => {} + let error_node = hir.node(error_node); + // `isNodeDescendantOf` + let is_in = + |node: Node, ancestor: Node| hir.find_ancestor(node, |n| n == ancestor).is_some(); + if of == file && (is_in(error_node, current_node) || is_in(current_node, error_node)) { + return None; } + Some(Reported::bare(self.place_of_current_node(current), 2751)) } } diff --git a/src/sema/check/errors_classes.rs b/src/sema/check/errors_classes.rs index beef668244ce..8904869296e5 100644 --- a/src/sema/check/errors_classes.rs +++ b/src/sema/check/errors_classes.rs @@ -99,10 +99,13 @@ impl<'p> Checker<'p, '_> { self.check_members_for_override_modifier(file, c, sym, base); for node in hir.ids(class.implements) { // `!IsEntityNameExpression(expr)`, whose type is the error type. - if let TypeNodeKind::Heritage(expression) = hir[node].kind { - let end = self.end_of_expr(file, expression); + if let TypeNodeKind::Heritage { expr, .. } = hir[node].kind { + let end = self.end_of_expr(file, expr); self.error_at((file, hir[node].pos, end), 2500, &[]); } + // `checkTypeReferenceNode`. `checkSourceElement` does not visit the element: + // `c.currentNode` stays the class until the type arguments are visited. + self.check_type_node_worker(file, node); if !matches!(hir[node].kind, TypeNodeKind::Ref { .. }) { continue; } @@ -138,13 +141,6 @@ impl<'p> Checker<'p, '_> { /// `checkBaseTypeAccessibility`: TS2675. A class with a private constructor can only be extended inside its own declaration. fn check_base_type_accessibility(&mut self, file: FileId, c: ClassId, apparent: TypeId) { - let TypeData::Anon { - origin: Origin::ClassStatic(class), - .. - } = *self.data(apparent) - else { - return; - }; let Some(&first) = self.signatures(apparent, true).first() else { return; }; @@ -152,10 +148,13 @@ impl<'p> Checker<'p, '_> { let hir = self.hir(file); if let Some((declared_in, func, _)) = self.sig_decl(declared) && self.hir(declared_in)[func].flags.contains(Flags::PRIVATE) + // `t.symbol`. tsgo dereferences nil for a type that has none. + && let Some(symbol) = self.symbol_of_type(apparent).and_then(|it| it.of_binder()) + // `GetClassLikeDeclarationOfSymbol(t.symbol)` is nil for an interface. && !(self.enclosing_classes(file, hir[c].extends).into_iter()) - .any(|around| self.class_sym(file, around) == class) + .any(|around| self.class_sym(file, around) == symbol) { - let name = super::errors_names_and_exports::fully_qualified_name(self, class, None); + let name = super::errors_names_and_exports::fully_qualified_name(self, symbol, None); self.error( file, hir.node(c).with(Part::Base), @@ -217,10 +216,10 @@ impl<'p> Checker<'p, '_> { for node in hir.ids(hir[i].extends) { if matches!( hir[node].kind, - TypeNodeKind::Error | TypeNodeKind::Heritage(_) + TypeNodeKind::Error | TypeNodeKind::Heritage { .. } ) { let end = match hir[node].kind { - TypeNodeKind::Heritage(expression) => self.end_of_expr(file, expression), + TypeNodeKind::Heritage { expr, .. } => self.end_of_expr(file, expr), _ => hir[node].end, }; self.error_at((file, hir[node].pos, end), 2499, &[]); diff --git a/src/sema/check/errors_decl.rs b/src/sema/check/errors_decl.rs index 4c0ab6923b00..cd5d7cf5cc7a 100644 --- a/src/sema/check/errors_decl.rs +++ b/src/sema/check/errors_decl.rs @@ -8,7 +8,7 @@ //! nameresolver.go. use super::*; -use crate::bind::{Decl, MemberOwner, PatParent, SymbolId}; +use crate::bind::{Decl, PatParent, SymbolId}; use smallvec::SmallVec; impl Checker<'_, '_> { @@ -133,12 +133,17 @@ impl Checker<'_, '_> { sym: Sym, decls: &[(FileId, Decl)], ) { - let lists: Vec<(FileId, Span, u32)> = decls + // With `declaration.Name()`, which is nil for `export default class {}`. + let lists: Vec<(FileId, Span, Option)> = decls .iter() .filter_map(|&(f, d)| match d { - Decl::Class(c) => Some((f, self.hir(f)[c].type_params, self.hir(f)[c].name_pos)), + Decl::Class(c) => { + let class = &self.hir(f)[c]; + let name = class.name.is_some().then_some(class.name_pos); + Some((f, class.type_params, name)) + } Decl::Interface(i) => { - Some((f, self.hir(f)[i].type_params, self.hir(f)[i].name_pos)) + Some((f, self.hir(f)[i].type_params, Some(self.hir(f)[i].name_pos))) } _ => None, }) @@ -181,7 +186,17 @@ impl Checker<'_, '_> { } if !identical { for l in lists.iter().filter(|l| l.0 == file) { - self.error_at((file, l.2, 0), 2428, &[Arg::Sym(sym)]); + match l.2 { + Some(name) => { + self.error_at((file, name, 0), 2428, &[Arg::Sym(sym)]); + } + // `c.error(nil, ..)` + None => { + let at = super::explain::NOWHERE; + let diagnostic = self.new_diagnostic(at, 2428, &[Arg::Sym(sym)]); + self.add_diagnostic_of(None, diagnostic); + } + } } } } @@ -209,33 +224,30 @@ impl Checker<'_, '_> { // The local symbol of a module or a namespace also lists the declarations exported // under the name. if is_checked && bound.symbol_of_declaration(node).idx() == i { + let current = CurrentNode::Node(file, self.hir(file).node(node)); + let saved = self.enter_source_element(current); self.check_variable_like_declaration(file, node); + self.current_source_element = saved; } } } } - /// The end of `checkVariableLikeDeclaration`, starting at `t := - /// c.convertAutoToAny(c.getTypeOfSymbol(symbol))`, except for the initializer. + /// The end of `checkVariableLikeDeclaration`, starting at `if ast.IsBigIntLiteral(name)`, + /// except for the initializer. pub(super) fn check_variable_like_declaration(&mut self, file: FileId, node: Decl) { let (own, hir) = ((file, node), self.hir(file)); // The source text of the default library is not stored: there is no name to report. if hir.text.is_empty() { return; } - // `checkIndexConstraints` has resolved the members of a class or an interface before they - // are checked. `checkTypeLiteral` checks the members first. - let declarations = match node { - Decl::Member(m) - if matches!( - self.bound(file).member_owner[m.idx()], - MemberOwner::TypeLiteral(_) - ) => - { - self.declarations_of_symbol_of_declaration(file, node) - } - _ => self.declarations_of_member(file, node), - }; + if let Decl::Member(m) = node + && hir[m].key == PropKey::None + && is_bigint_literal_at(hir, hir[m].name_pos) + { + self.error_at((file, hir[m].name_pos, 0), 1539, &[]); + } + let declarations = self.declarations_of_symbol_of_checked_declaration(file, node); if declarations.len() < 2 { return; } @@ -252,11 +264,13 @@ impl Checker<'_, '_> { Decl::Var(pat) | Decl::Param(pat) => (hir[pat].pos, self.end_of_pat(file, pat)), _ => return, }; + let start = super::spans::start_of_error_range(hir, start, end); // `DeclarationNameToString` - let (at, name) = ( - (file, start, end), - Arg::Bytes(&hir.text[start as usize..end as usize]), - ); + let name: &[u8] = match start == end { + true => b"(Missing)", + false => &hir.text[start as usize..end as usize], + }; + let (at, name) = ((file, start, end), Arg::Bytes(name)); let differs = if value_declaration == own { declarations.iter().any(|&d| { d != own @@ -289,9 +303,9 @@ impl Checker<'_, '_> { return; } // `getTypeOfSymbol`: `getTypeOfAccessors` adds no optionality. - let t = if let Some(prototype) = self.get_type_of_prototype_property(symbol) { - prototype - } else if self.files().flags(symbol).intersects(SymFlags::ACCESSOR) { + let t = if self.files().flags(symbol).intersects(SymFlags::ACCESSOR) + || self.is_prototype_symbol(symbol) + { let ty = self.type_of_symbol(symbol); self.convert_auto_to_any(ty) } else { @@ -316,24 +330,6 @@ impl Checker<'_, '_> { .extend(related); } - /// `getTypeOfPrototypeProperty`, if `symbol` has `SymbolFlagsPrototype`: it is the `prototype` - /// that `bindClassLikeDeclaration` puts among the exports of a class, which a static member of - /// that name declares too. - fn get_type_of_prototype_property(&mut self, symbol: Sym) -> Option { - let files = self.files(); - if files.symbol(symbol).name != known::prototype { - return None; - } - let class = files.parent_of_symbol(symbol)?; - if !files.flags(class).contains(SymFlags::CLASS) - || files.export(class, known::prototype) != Some(files.canonical(symbol)) - { - return None; - } - let constructor = self.type_of_symbol(class); - self.type_of_property(constructor, known::prototype) - } - /// `convertAutoToAny(getWidenedTypeForVariableLikeDeclaration(declaration, false))`. For /// `symbol.ValueDeclaration` it is `getTypeOfSymbol(symbol)`. fn get_widened_type_for_variable_like_declaration( diff --git a/src/sema/check/errors_declaration_emit.rs b/src/sema/check/errors_declaration_emit.rs index b29fa77a0126..3e4c1344bac5 100644 --- a/src/sema/check/errors_declaration_emit.rs +++ b/src/sema/check/errors_declaration_emit.rs @@ -13,18 +13,20 @@ use super::enclosing_declaration::Enclosing; use super::errors_isolated_declarations::Emit; use super::print::{ DECLARATION_EMIT_NODE_BUILDER_FLAGS, Report, SymbolTracker, - WRITE_CLASS_EXPRESSION_AS_TYPE_LITERAL, Written, YieldModuleSymbol, push_access, + WRITE_CLASS_EXPRESSION_AS_TYPE_LITERAL, Written, YieldModuleSymbol, }; use super::sink::held; use super::*; use crate::bind::{ClassOwner, Decl, FnOwner, MemberOwner, Parent, PatParent, ScopeId, ScopeKind}; -use crate::config::compare_strings_case_insensitive; +use crate::config::{change_extension, compare_strings_case_insensitive}; use crate::json::Json; -use crate::program::source_file_may_be_emitted; +use crate::program::{get_output_extension, source_file_may_be_emitted}; use crate::resolve::{ - JsxEmit, contains_path, ensure_path_is_non_module_name, get_relative_path_from_directory, - get_root_length, is_declaration_file_name, is_relative, is_rooted_disk_path, join, - known_extension, node_module_path_parts, path_is_relative, remove_file_extension, + JsxEmit, ObjectKind, ancestors, contains_path, ensure_path_is_non_module_name, + equate_string_case_insensitive, get_base_file_name, get_declaration_file_extension, + get_relative_path_from_directory, get_root_length, has_ts_implementation_extension, inside, + is_declaration_file_name, is_relative, is_rooted_disk_path, join, known_extension, + node_module_path_parts, normalize_path, object_kind, path_is_relative, remove_file_extension, }; use bstr::ByteSlice; use bun_core::strings; @@ -306,6 +308,11 @@ const MODIFIERS: [(Flags, &[u8]); 15] = [ /// `IsNonContextualKeyword`: the reserved words, and those of strict mode. fn is_non_contextual_keyword(word: &[u8]) -> bool { + is_reserved_word(word) || bun_core::lexer_tables::is_strict_mode_reserved_word(word) +} + +/// `isReservedWord` +pub(super) fn is_reserved_word(word: &[u8]) -> bool { matches!( word, b"break" @@ -344,15 +351,6 @@ fn is_non_contextual_keyword(word: &[u8]) -> bool { | b"void" | b"while" | b"with" - | b"implements" - | b"interface" - | b"let" - | b"package" - | b"private" - | b"protected" - | b"public" - | b"static" - | b"yield" ) } @@ -825,6 +823,7 @@ impl<'p, 's> Checker<'p, 's> { // All these queries run after everything is checked: a cycle through here is not reported // as an error. let saved = self.relation_too_complex; + let reported = self.reported.len(); self.eager.push(self.stack.len()); let (text, found, isolated_declarations) = { let mut emit = DeclarationEmit::new(self, file); @@ -842,6 +841,11 @@ impl<'p, 's> Checker<'p, 's> { }; self.eager.pop(); self.relation_too_complex = saved; + // `getDeclarationDiagnostics` returns the diagnostics of the transformer. Those of the + // checker are read by `checkSourceFile`, which has run. + if !self.emits_first() { + self.reported.truncate(reported); + } // `emitDeclarationFile`: `emitSkipped`, if the transformer has diagnostics. let mut is_skipped = !found.is_empty(); if let Some(isolated_declarations) = isolated_declarations { @@ -1084,16 +1088,12 @@ impl<'p, 's> Checker<'p, 's> { } else { self.symbol_chain_ex(symbol, at, meaning, YieldModuleSymbol::No, EndOfChain::Yes) }; + let chain: Vec = (chain.into_iter()) + .map(|part| self.target_of_module_clone(part)) + .collect(); // "add neverAsciiEscape for GH#39027" - let escapes_non_ascii = self.node_of_enclosing_declaration(at) != Node::FILE; - // `createExpressionFromSymbolChain` - let mut expression = self.symbol_text(chain[0]); - for &part in &chain[1..] { - let name = self.symbol_text(part); - let is_enum_member = self.flags_of(part).contains(SymFlags::ENUM_MEMBER); - push_access(&mut expression, &name, is_enum_member, escapes_non_ascii); - } - expression + let never_ascii_escape = self.node_of_enclosing_declaration(at) == Node::FILE; + self.create_expression_from_symbol_chain(&chain, at, never_ascii_escape) } /// `enclosingDeclaration`, if it is one of the nodes of `isEnclosingDeclaration` that the @@ -2290,7 +2290,7 @@ impl<'p, 's> Checker<'p, 's> { /// The part of `getContainersOfSymbol` for the class expression `e` on the right of `a.b = class ..`: the module for /// `module.exports = ..` and `exports.b = ..`, otherwise what `a` resolves to. - fn container_of_assigned_class_expression(&self, file: FileId, e: ExprId) -> Option { + fn container_of_assigned_class_expression(&mut self, file: FileId, e: ExprId) -> Option { let (hir, bound, files) = (self.hir(file), self.bound(file), self.files()); let Parent::Expr(assignment) = bound.expr_parent[e.idx()] else { return None; @@ -4959,28 +4959,50 @@ impl<'p> DeclarationEmit<'_, 'p, '_> { if self.is_private_function(f) { return Vec::new(); } - let hir = self.c.hir(self.file()); - let function = hir[f]; + let function = self.c.hir(self.file())[f]; let mut parameters = Vec::with_capacity(function.params.len() + 1); - if function.this_ty(hir).is_some() { - // `ensureParameter` - let ty = match self.ensure_type(hir.node(function.this_param), true) { - Ensured::Type(ty) => ty, - Ensured::Nothing | Ensured::Initializer(_) => Vec::new(), - }; - parameters.push(Element { - range: None, - text: [b"this: ", &ty[..]].concat(), - }); + for p in function + .this_param + .some() + .into_iter() + .chain(function.params.iter()) + { + parameters.push(self.ensure_parameter_in_list(p)); } - for p in function.params.iter() { - let loc = hir[p].loc; - parameters.push(Element { - range: (loc.end != 0).then_some((loc.pos as usize, loc.end as usize)), - text: self.ensure_parameter(p), + self.list_text(parameters, ListFormat::SINGLE_LINE) + } + + /// `updateAccessorParamList`: the parameters, with `, ` between them. + fn update_accessor_param_list(&mut self, f: FnId, is_private: bool) -> Vec { + let function = self.c.hir(self.file())[f]; + let mut new_params = Vec::with_capacity(2); + if !is_private && let Some(this_param) = function.this_param.some() { + new_params.push(self.ensure_parameter_in_list(this_param)); + } + if function.kind == FnKind::Setter { + let value_param = function.params.iter().next().filter(|_| !is_private); + new_params.push(match value_param { + Some(value_param) => self.ensure_parameter_in_list(value_param), + None => Element { + range: None, + text: if is_private { + b"value".to_vec() + } else { + b"value: any".to_vec() + }, + }, }); } - self.list_text(parameters, ListFormat::SINGLE_LINE) + self.list_text(new_params, ListFormat::SINGLE_LINE) + } + + /// `ensureParameter`, as an element of `Parameters`. + fn ensure_parameter_in_list(&mut self, p: ParamId) -> Element { + let loc = self.c.hir(self.file())[p].loc; + Element { + range: (loc.end != 0).then_some((loc.pos as usize, loc.end as usize)), + text: self.ensure_parameter(p), + } } /// `emitListItems`: see `Writer::emit_list_items`. @@ -5027,7 +5049,12 @@ impl<'p> DeclarationEmit<'_, 'p, '_> { } else { b"" }; - let name = self.text_of(Written::BindingName(hir[p].pat)); + // The name that the reparser gives the parameter of a `@this` tag is not in the source. + let name = if self.c.is_this_parameter(file, p) { + b"this".to_vec() + } else { + self.text_of(Written::BindingName(hir[p].pat)) + }; [rest, &name[..], question, &ensured.text()[..]].concat() } @@ -5101,11 +5128,8 @@ impl<'p> DeclarationEmit<'_, 'p, '_> { if self.c.iso_report_dynamic_name(isolated_declarations, m) { return None; } - } - // `IsLateBound` - else if let Some(key) = dynamic_name - && !(is_entity_name_expression(self.c.hir(self.file()), key) - && self.c.member_name(self.file(), member.key).is_some()) + } else if let Some(key) = dynamic_name + && !(self.c.is_late_bound(self.file(), m) && is_entity_name_expression(hir, key)) { return None; } @@ -5174,37 +5198,15 @@ impl<'p> DeclarationEmit<'_, 'p, '_> { Some([&modifiers[..], b"constructor(", ¶meters[..], b");"].concat()) } MemberKind::Getter => { - if !is_private { - self.visit_type(hir[f].this_ty(hir), false); - } + let parameters = self.update_accessor_param_list(f, is_private); let ensured = self.ensure_type(hir.node(m), false); - let name = [&modifiers[..], b"get ", &name[..]].concat(); - Some([&name[..], b"()", &ensured.text()[..], b";"].concat()) + let name = [&modifiers[..], b"get ", &name[..], b"("].concat(); + Some([&name[..], ¶meters[..], b")", &ensured.text()[..], b";"].concat()) } - // `updateAccessorParamList` MemberKind::Setter => { - let mut value = None; - if !is_private { - self.visit_type(hir[f].this_ty(hir), false); - if let Some(parameter) = hir[f].params.iter().next() { - let loc = hir[parameter].loc; - let element = Element { - range: (loc.end != 0) - .then_some((loc.pos as usize, loc.end as usize)), - text: self.ensure_parameter(parameter), - }; - value = Some(self.list_text(vec![element], ListFormat::SINGLE_LINE)); - } - } - let value = value.unwrap_or_else(|| { - if is_private { - b"value".to_vec() - } else { - b"value: any".to_vec() - } - }); + let parameters = self.update_accessor_param_list(f, is_private); let name = [&modifiers[..], b"set ", &name[..]].concat(); - Some([&name[..], b"(", &value[..], b");"].concat()) + Some([&name[..], b"(", ¶meters[..], b");"].concat()) } MemberKind::IndexSignature => { self.visit_type(hir[f].ret, false); @@ -5392,7 +5394,7 @@ impl<'p> DeclarationEmit<'_, 'p, '_> { } TypeNodeKind::Predicate { ty, .. } => self.visit_type(ty, false), TypeNodeKind::Error - | TypeNodeKind::Heritage(_) + | TypeNodeKind::Heritage { .. } | TypeNodeKind::Keyword(_) | TypeNodeKind::StringLit(_) | TypeNodeKind::NumberLit(_) @@ -5615,6 +5617,19 @@ enum Matching { Pattern, } +impl Matching { + /// How a key of `exports` or `imports` is matched. + fn of_key(key: &[u8]) -> Matching { + if key.ends_with(b"/") { + Matching::Directory + } else if strings::contains_char(key, b'*') { + Matching::Pattern + } else { + Matching::Exact + } + } +} + /// `PathIsBareSpecifier` fn path_is_bare_specifier(path: &[u8]) -> bool { get_root_length(path) == 0 && !path_is_relative(path) @@ -5679,12 +5694,82 @@ fn package_name_from_types_package_name(name: &[u8]) -> Vec { } } -/// `tryGetModuleNameFromExportsOrImports` for `exports`: the specifier under which an importer -/// reaches the file `target` in the package in `package_directory`. `swapped`: `target` with its -/// JavaScript output extension. Empty: it cannot be imported. -fn module_name_from_exports( - target: &[u8], - swapped: &[u8], +/// `GetDeclarationEmitExtensionForPath` +fn get_declaration_emit_extension_for_path(path: &[u8]) -> Vec { + match known_extension(path) { + b".mjs" | b".mts" | b".d.mts" => b".d.mts".to_vec(), + b".cjs" | b".cts" | b".d.cts" => b".d.cts".to_vec(), + b".ts" | b".d.ts" | b".tsx" | b".js" | b".jsx" => b".d.ts".to_vec(), + _ => { + let base = get_base_file_name(path); + match strings::last_index_of_char(base, b'.') { + Some(at) => [&b".d"[..], &base[at..], b".ts"].concat(), + None => b".d.ts".to_vec(), + } + } + } +} + +/// `ChangeFullExtension` +fn change_full_extension(path: &[u8], extension: &[u8]) -> Vec { + match get_declaration_file_extension(path) { + b"" => change_extension(path, extension), + of_declaration => [&path[..path.len() - of_declaration.len()], extension].concat(), + } +} + +/// `HasPrefixAndSuffixWithoutOverlap` +fn has_prefix_and_suffix_without_overlap( + text: &[u8], + prefix: &[u8], + suffix: &[u8], + is_case_sensitive: bool, +) -> bool { + if prefix.len() + suffix.len() > text.len() { + return false; + } + let (start, end) = (&text[..prefix.len()], &text[text.len() - suffix.len()..]); + match is_case_sensitive { + true => start == prefix && end == suffix, + false => { + equate_string_case_insensitive(start, prefix) + && equate_string_case_insensitive(end, suffix) + } + } +} + +/// `prefersTsExtension` +fn prefers_ts_extension(allowed_endings: &[Ending]) -> bool { + let priority = |ending: Ending| { + allowed_endings + .iter() + .position(|&allowed| allowed == ending) + }; + priority(Ending::Ts).is_some_and(|ts| priority(Ending::Js).is_some_and(|js| ts < js)) +} + +/// What `tryGetModuleNameFromExportsOrImports` compares with the strings in `exports` or `imports`. +struct TargetFile<'a> { + /// `targetFilePath` + path: &'a [u8], + /// `extensionSwappedTarget`. Empty: `path` has no TypeScript extension. + extension_swapped: Vec, + /// `outputFile`, `declarationFile`. Empty for `exports`. + output_file: Vec, + declaration_file: Vec, + /// `canTryTsExtension` + can_try_ts_extension: bool, + /// `options.Jsx == JsxEmitPreserve` + preserves_jsx: bool, + /// `UseCaseSensitiveFileNames` + is_case_sensitive: bool, +} + +/// `tryGetModuleNameFromExportsOrImports`: the specifier under which an importer reaches `target` +/// through `exports`, a value in the `exports` or `imports` of the `package.json` in +/// `package_directory`. Empty: it cannot be imported. +fn try_get_module_name_from_exports_or_imports( + target: &TargetFile<'_>, package_directory: &[u8], package_name: &[u8], exports: &Json, @@ -5693,47 +5778,101 @@ fn module_name_from_exports( ) -> Vec { match exports { Json::String(value) => { - let pattern = join(package_directory, value); - for candidate in [swapped, target] { - if candidate.is_empty() { - continue; + let path_or_pattern = join(package_directory, value); + let is_case_sensitive = target.is_case_sensitive; + match matching { + Matching::Exact => { + let is_at_path = |candidate: &[u8]| { + !candidate.is_empty() + && compare_paths(candidate, &path_or_pattern, is_case_sensitive).is_eq() + }; + if is_at_path(&target.extension_swapped) + || is_at_path(target.path) + || is_at_path(&target.output_file) + || is_at_path(&target.declaration_file) + { + return package_name.to_vec(); + } } - match matching { - Matching::Exact => { - if candidate == pattern { - return package_name.to_vec(); - } + Matching::Directory => { + let is_inside = |candidate: &[u8]| { + !candidate.is_empty() + && contains_path(&path_or_pattern, candidate, is_case_sensitive) + }; + let fragment = |candidate: &[u8]| { + get_relative_path_from_directory( + &path_or_pattern, + candidate, + is_case_sensitive, + ) + }; + let after_value = |candidate: &[u8]| { + let fragment = fragment(candidate); + let (value, fragment) = (value.as_slice(), fragment.as_slice()); + normalized_name(&[package_name, b"/", value, b"/", fragment].concat()) + }; + // The arguments are in this order there. + if target.can_try_ts_extension + && contains_path(target.path, &path_or_pattern, is_case_sensitive) + { + return after_value(target.path); } - Matching::Directory => { - if candidate - .strip_prefix(pattern.as_slice()) - .is_some_and(|rest| rest.starts_with(b"/")) - { - let fragment = relative_normalized::(&pattern, candidate); - return normalized_name( - &[package_name, b"/", value.as_slice(), b"/", fragment].concat(), - ); - } + if is_inside(&target.extension_swapped) { + return after_value(&target.extension_swapped); } - Matching::Pattern => { - let (leading, trailing) = strings::split_once(&pattern, b"*") - .unwrap_or((pattern.as_slice(), b"")); - if leading.len() + trailing.len() <= candidate.len() - && candidate.starts_with(leading) - && candidate.ends_with(trailing) - { + if !target.can_try_ts_extension && is_inside(target.path) { + return after_value(target.path); + } + if is_inside(&target.output_file) { + return inside(package_name, &fragment(&target.output_file)); + } + if is_inside(&target.declaration_file) { + let js_extension = + js_extension_for_file(&target.declaration_file, target.preserves_jsx); + let fragment = fragment(&target.declaration_file); + return inside(package_name, &change_extension(&fragment, js_extension)); + } + } + Matching::Pattern => { + let (leading, trailing) = strings::split_once(&path_or_pattern, b"*") + .unwrap_or((path_or_pattern.as_slice(), b"")); + // `replaceFirstStar(packageName, starReplacement)` + let substituted = |candidate: &[u8]| { + let is_match = !candidate.is_empty() + && has_prefix_and_suffix_without_overlap( + candidate, + leading, + trailing, + is_case_sensitive, + ); + is_match.then(|| { let star = &candidate[leading.len()..candidate.len() - trailing.len()]; - return package_name.replacen(b"*", star, 1); - } + package_name.replacen(b"*", star, 1) + }) + }; + let extension_swapped = target.extension_swapped.as_slice(); + let output_file = target.output_file.as_slice(); + let sources = match target.can_try_ts_extension { + true => [target.path, extension_swapped, output_file], + false => [extension_swapped, target.path, output_file], + }; + if let Some(name) = sources.into_iter().find_map(&substituted) { + return name; + } + let js_extension = + js_extension_for_file(&target.declaration_file, target.preserves_jsx); + if !js_extension.is_empty() + && let Some(name) = substituted(&target.declaration_file) + { + return change_full_extension(&name, js_extension); } } } } Json::Array(list) => { for entry in list { - let name = module_name_from_exports( + let name = try_get_module_name_from_exports_or_imports( target, - swapped, package_directory, package_name, entry, @@ -5755,9 +5894,8 @@ fn module_name_from_exports( { continue; } - let name = module_name_from_exports( + let name = try_get_module_name_from_exports_or_imports( target, - swapped, package_directory, package_name, value, @@ -5775,9 +5913,8 @@ fn module_name_from_exports( } /// `tryGetModuleNameFromExports` -fn module_name_from_package_exports( - target: &[u8], - swapped: &[u8], +fn try_get_module_name_from_exports( + target: &TargetFile<'_>, package_directory: &[u8], package_name: &[u8], exports: &Json, @@ -5785,34 +5922,24 @@ fn module_name_from_package_exports( ) -> Vec { // `IsSubpaths` if let Json::Object(entries) = exports - && !entries.is_empty() - && entries.iter().all(|entry| entry.0.starts_with(b".")) + && object_kind(entries) == ObjectKind::Subpaths { for (key, value) in entries { - let matching = if key.ends_with(b"/") { - Matching::Directory - } else if bun_core::strings::contains_char(key, b'*') { - Matching::Pattern - } else { - Matching::Exact - }; - let name = module_name_from_exports( + let name = try_get_module_name_from_exports_or_imports( target, - swapped, package_directory, &normalized_name(&[package_name, b"/", key.as_slice()].concat()), value, conditions, - matching, + Matching::of_key(key), ); if !name.is_empty() { return name; } } } - module_name_from_exports( + try_get_module_name_from_exports_or_imports( target, - swapped, package_directory, package_name, exports, @@ -5821,6 +5948,13 @@ fn module_name_from_package_exports( ) } +/// `isImports` and `preferTsExtension` of `tryGetModuleNameFromExportsOrImports`. +#[derive(Copy, Clone)] +struct TargetFileOptions { + is_imports: bool, + prefers_ts_extension: bool, +} + impl<'p, 's> Checker<'p, 's> { /// The relative specifiers in `file`, in source order. fn relative_specifiers_of(&self, file: FileId) -> Vec<&'p [u8]> { @@ -5960,11 +6094,8 @@ impl<'p, 's> Checker<'p, 's> { ] .concat() }; - let priority = |ending: Ending| allowed.iter().position(|&allowed| allowed == ending); - let js_priority = priority(Ending::Js); - if matches!(extension, b".mts" | b".cts") - && priority(Ending::Ts).is_some_and(|ts| js_priority.is_some_and(|js| ts < js)) - { + let js_priority = allowed.iter().position(|&ending| ending == Ending::Js); + if matches!(extension, b".mts" | b".cts") && prefers_ts_extension(allowed) { return file_name.to_vec(); } if matches!(extension, b".d.mts" | b".d.cts" | b".mts" | b".cts") { @@ -6020,6 +6151,144 @@ impl<'p, 's> Checker<'p, 's> { } } + /// `GetConditions` + fn get_conditions(&self, mode: ResolutionMode) -> Vec<&'p [u8]> { + let options = self.files().options; + let is_import = mode == ResolutionMode::Import + || mode == ResolutionMode::None && !options.resolves_like_node; + let mut conditions = vec![ + if is_import { + &b"import"[..] + } else { + b"require" + }, + b"types", + ]; + if options.resolves_like_node { + conditions.push(b"node"); + } + conditions.extend(options.custom_conditions.iter().map(Vec::as_slice)); + conditions + } + + /// `getOutputPathWithoutChangingExtension` + fn get_output_path_without_changing_extension( + &self, + input_file_name: &[u8], + output_directory: &[u8], + ) -> Vec { + let files = self.files(); + match files.common_source_directory { + Some(common) if !output_directory.is_empty() => { + let relative = get_relative_path_from_directory( + common, + input_file_name, + files.is_case_sensitive, + ); + join(output_directory, &relative) + } + _ => input_file_name.to_vec(), + } + } + + /// The file at `path`, for `tryGetModuleNameFromExportsOrImports`. + fn target_file<'a>(&self, path: &'a [u8], options: TargetFileOptions) -> TargetFile<'a> { + let TargetFileOptions { + is_imports, + prefers_ts_extension, + } = options; + let files = self.files(); + let options = files.options; + let preserves_jsx = options.jsx == JsxEmit::Preserve; + let mut target = TargetFile { + path, + extension_swapped: Vec::new(), + output_file: Vec::new(), + declaration_file: Vec::new(), + // `HasImplementationTSFileExtension` + can_try_ts_extension: prefers_ts_extension + && has_ts_implementation_extension(path) + && !is_declaration_file_name(path), + preserves_jsx, + is_case_sensitive: files.is_case_sensitive, + }; + // `HasTSFileExtension` + if matches!( + known_extension(path), + b".ts" | b".tsx" | b".d.ts" | b".cts" | b".d.cts" | b".mts" | b".d.mts" + ) { + target.extension_swapped = [ + remove_file_extension(path), + js_extension_for_file(path, preserves_jsx), + ] + .concat(); + } + if is_imports { + // `GetOutputJSFileNameWorker` + let moved = self.get_output_path_without_changing_extension(path, &options.out_dir); + target.output_file = change_extension(&moved, get_output_extension(options, path)); + // `GetOutputDeclarationFileNameWorker` + let directory = match options.declaration_dir.as_slice() { + b"" => options.out_dir.as_slice(), + declaration_dir => declaration_dir, + }; + let moved = self.get_output_path_without_changing_extension(path, directory); + target.declaration_file = + change_extension(&moved, &get_declaration_emit_extension_for_path(path)); + } + target + } + + /// `tryGetModuleNameFromPackageJsonImports`: the `#name` under which `importing` reaches the + /// file at `module_file_name` through the `imports` of its package. Empty: there is none. + fn try_get_module_name_from_package_json_imports( + &self, + module_file_name: &[u8], + importing: FileId, + import_mode: ResolutionMode, + prefers_ts_extension: bool, + ) -> Vec { + let files = self.files(); + let options = files.options; + if !options.resolve_package_json_imports { + return Vec::new(); + } + let package_directory = self.package_json_directory(importing); + let package_json = files.package_jsons.get(package_directory); + let Some(Json::Object(entries)) = package_json.and_then(|json| json.get(b"imports")) else { + return Vec::new(); + }; + let conditions = self.get_conditions(import_mode); + let target = self.target_file( + module_file_name, + TargetFileOptions { + is_imports: true, + prefers_ts_extension, + }, + ); + for (key, value) in entries { + if key == b"#" || key == b"#/" || !key.starts_with(b"#") { + continue; + } + // Only `nodenext` and `bundler` resolve such a key. + if key.starts_with(b"#/") && options.resolves_like_node16 { + continue; + } + let name = try_get_module_name_from_exports_or_imports( + &target, + package_directory, + key, + value, + &conditions, + Matching::of_key(key), + ); + if !name.is_empty() { + return name; + } + } + Vec::new() + } + /// `tryGetModuleNameAsNodeModule`: the specifier `importing` uses for the file at `path`, which /// is in `node_modules`. Empty: it has no specifier through `node_modules`. fn try_get_module_name_as_node_module( @@ -6056,45 +6325,22 @@ impl<'p, 's> Checker<'p, 's> { } _ => mode, }; - // `GetConditions` - let is_import = mode == ResolutionMode::Import - || mode == ResolutionMode::None && !options.resolves_like_node; - let mut conditions = vec![ - if is_import { - &b"import"[..] - } else { - b"require" - }, - b"types", - ]; - if options.resolves_like_node { - conditions.push(b"node"); - } - conditions.extend(options.custom_conditions.iter().map(Vec::as_slice)); - let swapped = if matches!( - known_extension(path), - b".ts" | b".tsx" | b".d.ts" | b".cts" | b".d.cts" | b".mts" | b".d.mts" - ) { - let preserves_jsx = options.jsx == JsxEmit::Preserve; - [ - remove_file_extension(path), - js_extension_for_file(path, preserves_jsx), - ] - .concat() - } else { - Vec::new() - }; // A file that `exports` does not expose has no specifier through // `node_modules`. - return module_name_from_package_exports( - path, - &swapped, + return try_get_module_name_from_exports( + &self.target_file( + path, + TargetFileOptions { + is_imports: false, + prefers_ts_extension: false, + }, + ), package_directory, &package_name_from_types_package_name( &package_directory[top_level_package_name + 1..], ), exports, - &conditions, + &self.get_conditions(mode), ); } // The specifier of the main file is the package name. @@ -6256,6 +6502,7 @@ impl<'p, 's> Checker<'p, 's> { path, target, importing, + target_mode, &allowed_endings, paths_only, ); @@ -6291,6 +6538,7 @@ impl<'p, 's> Checker<'p, 's> { module_file_name: &[u8], target: FileId, importing: FileId, + import_mode: ResolutionMode, allowed_endings: &[Ending], paths_only: bool, ) -> Vec { @@ -6314,13 +6562,14 @@ impl<'p, 's> Checker<'p, 's> { relative_path = self.process_ending(&ensure_path_is_non_module_name(relative), allowed_endings); } + if options.paths.is_empty() && !options.resolve_package_json_imports { + return relative_path; + } // `GetPathsBasePath` let base_directory = match options.paths_base_dir.as_slice() { b"" => options.base_dir.as_slice(), reported => reported, }; - // `tryGetModuleNameFromPackageJsonImports` is not ported: no `#name` specifier is generated - // yet. // `getRelativePathIfInSameVolume` let relative_to_base_url = get_relative_path_from_directory( base_directory, @@ -6334,11 +6583,22 @@ impl<'p, 's> Checker<'p, 's> { relative_path }; } - let maybe_non_relative = self.try_get_module_name_from_paths( - &relative_to_base_url, - allowed_endings, - base_directory, - ); + let mut maybe_non_relative = Vec::new(); + if !paths_only { + maybe_non_relative = self.try_get_module_name_from_package_json_imports( + module_file_name, + importing, + import_mode, + prefers_ts_extension(allowed_endings), + ); + } + if maybe_non_relative.is_empty() { + maybe_non_relative = self.try_get_module_name_from_paths( + &relative_to_base_url, + allowed_endings, + base_directory, + ); + } if paths_only { return maybe_non_relative; } @@ -6350,11 +6610,16 @@ impl<'p, 's> Checker<'p, 's> { b"" => options.base_dir.as_slice(), config_path => dirname::(config_path), }; - let is_internal = |path: &[u8]| contains_path(project_directory, path, true); + let is_internal = + |path: &[u8]| contains_path(project_directory, path, files.is_case_sensitive); // The import crosses the directory of the configuration file, or goes from one package to another. return if is_internal(source_directory) != is_internal(module_file_name) - || files.module(importing).package_json_directory - != files.module(target).package_json_directory + || self.package_json_directory(importing) + != self.nearest_ancestor_directory_with_package_json( + module_file_name, + target, + importing, + ) { maybe_non_relative } else { @@ -6371,6 +6636,42 @@ impl<'p, 's> Checker<'p, 's> { } } + /// `GetNearestAncestorDirectoryWithPackageJson` of the directory of `file`. Empty: none. + fn package_json_directory(&self, file: FileId) -> &'p [u8] { + let directory = self.files().module(file).package_json_directory; + if directory.is_some() { + self.atoms().bytes(directory) + } else { + b"" + } + } + + /// `GetNearestAncestorDirectoryWithPackageJson(GetDirectoryPath(path))` of a path that leads to + /// `target`, for an import in `importing`. For another path than the name of `target` (through + /// a link, of a copy of its package) the file system is not at hand: it is the nearest + /// directory that is known to have a `package.json`, which are those of the two files, the keys + /// of `package_jsons`, and the package in `node_modules` that `path` is in. Empty: none. + fn nearest_ancestor_directory_with_package_json<'a>( + &'a self, + path: &'a [u8], + target: FileId, + importing: FileId, + ) -> &'a [u8] { + let of_target = self.package_json_directory(target); + if path == self.files().module(target).file_name() { + return of_target; + } + let of_files = [of_target, self.package_json_directory(importing)]; + let package_root = node_module_path_parts(path).map(|parts| parts.2); + ancestors(dirname::(path)) + .find(|&directory| { + of_files.contains(&directory) + || package_root == Some(directory.len()) + || self.files().package_jsons.contains_key(directory) + }) + .unwrap_or_default() + } + /// `tryGetModuleNameFromRootDirs` fn try_get_module_name_from_root_dirs( &self, @@ -6458,7 +6759,7 @@ impl<'p, 's> Checker<'p, 's> { Some(output_dts.to_vec()) } - /// `ResolvedFileName` of an import of `importing`. + /// `ResolvedFileName` of an import of `importing`, normalized. fn resolved_file_name_of_import( &self, importing: FileId, @@ -6469,7 +6770,7 @@ impl<'p, 's> Checker<'p, 's> { let importer = files.module(importing); let mut redirected = importer.redirected_imports.iter(); if let Some(&(_, _, name)) = redirected.find(|it| it.0 == specifier && it.1 == mode) { - return self.atoms().bytes(name).to_vec(); + return normalize_path(self.atoms().bytes(name).to_vec()); } let path = files .module(importer.imports[&(specifier, mode)]) @@ -6767,8 +7068,16 @@ fn can_produce_diagnostics(kind: Kind) -> bool { fn get_name_of_declaration(hir: &hir::File, node: Node) -> Node { match hir.data(node) { NodeData::Expr(e) => match hir[e].kind { - // `GetElementOrPropertyAccessName` - ExprKind::Assign { target, .. } => hir.name(hir.node(target)), + // `GetElementOrPropertyAccessName`, or else the left operand. + ExprKind::Assign { target, .. } => match hir[target].kind { + ExprKind::Index { index, .. } + if is_string_or_numeric_literal_like_in_parentheses(hir, index) => + { + hir.node(index) + } + ExprKind::Index { .. } => hir.node(target), + _ => hir.name(hir.node(target)), + }, _ => hir.name(node), }, _ => hir.name(node), diff --git a/src/sema/check/errors_declaration_emit/commonjs.rs b/src/sema/check/errors_declaration_emit/commonjs.rs index 0c59444841ee..ff1c99b0c1c8 100644 --- a/src/sema/check/errors_declaration_emit/commonjs.rs +++ b/src/sema/check/errors_declaration_emit/commonjs.rs @@ -458,10 +458,12 @@ impl<'p> DeclarationEmit<'_, 'p, '_> { if !hir.is_js { return Vec::new(); } - // `thisPropertyAssignmentKey`: the name, `isStatic`. + // `thisPropertyAssignmentKey`: the name, `isStatic`. `getThisPropertyAssignmentKey`: a name + // that is dynamic, or whose text `TryGetTextOfPropertyName` does not know (`[+1]`), is a + // key of its own, which no assignment has. let mut seen: Vec<(Atom, bool)> = Vec::new(); for m in hir[c].members.iter() { - if let Some(name) = self.c.member_name(file, hir[m].key) { + if let Some(name) = hir[m].key.name() { seen.push((name, hir[m].flags.contains(Flags::STATIC))); } } diff --git a/src/sema/check/errors_duplicates.rs b/src/sema/check/errors_duplicates.rs index 2bfafced2cb9..6fa202ba405d 100644 --- a/src/sema/check/errors_duplicates.rs +++ b/src/sema/check/errors_duplicates.rs @@ -58,22 +58,6 @@ impl Checker<'_, '_> { self.check_static_property_name_conflicts(file); self.check_external_module_exports(file); self.report_redeclarations(file); - let hir = self.hir(file); - let lists = hir - .fns - .iter() - .map(|f| f.type_params) - .chain(hir.classes.iter().map(|c| c.type_params)) - .chain(hir.interfaces.iter().map(|i| i.type_params)) - .chain(hir.aliases.iter().map(|a| a.type_params)); - // `checkTypeParameters` - for params in lists { - for (i, p) in params.iter().enumerate() { - if (params.iter().take(i)).any(|earlier| hir[earlier].name == hir[p].name) { - self.report_on_declaration_name(file, Decl::TypeParam(p), 2300); - } - } - } } /// `getAdjustedNodeForError`: the start of the name of `decl`, or of `decl` itself if it has no name. @@ -83,7 +67,7 @@ impl Checker<'_, '_> { Decl::Var(pat) | Decl::Param(pat) | Decl::Require(pat) => hir[pat].pos, Decl::Fn(f) if hir[f].kind == FnKind::Decl => hir[f].name_pos, Decl::Class(c) if matches!(bound.class_owner[c.idx()], ClassOwner::Stmt(_)) => { - hir[c].name_pos + self.error_range_of_class(file, c).0 } Decl::Interface(i) => hir[i].name_pos, Decl::Alias(a) => hir[a].name_pos, @@ -189,7 +173,7 @@ impl Checker<'_, '_> { )) } - fn report_on_declaration_name(&mut self, file: FileId, node: Decl, message: u32) { + pub(super) fn report_on_declaration_name(&mut self, file: FileId, node: Decl, message: u32) { if let Some(diagnostic) = self.new_diagnostic_for_declaration_name(file, node, message) { self.add_diagnostic(diagnostic); } @@ -226,7 +210,8 @@ impl Checker<'_, '_> { // A member name can be a string literal or a computed name, so the range covers the whole name node. Decl::Member(_) | Decl::Property(_) | Decl::EnumMember(_) => { let start = self.declaration_name_start(file, decl)?; - return Some((start, self.end_of_name_at(file, start))); + let end = self.end_of_name_at(file, start); + return Some((super::spans::start_of_error_range(hir, start, end), end)); } _ => self.declaration_name_start(file, decl)?, }; @@ -264,6 +249,22 @@ impl Checker<'_, '_> { name == known::empty } + /// `getAdjustedNodeForError` for a declaration of a symbol that `mergeSymbol` is given: the + /// name of a module augmentation is a string literal. + fn place_of_merged_declaration( + &self, + file: FileId, + decl: Decl, + ) -> Option { + match decl { + Decl::Module(m) => Some(self.place_of_token(file, self.hir(file)[m].name_pos)), + Decl::ExportsProperty(e) | Decl::Expando(e) | Decl::ThisProperty(e) => { + self.place_of_assignment_declaration_name(file, e) + } + _ => self.place_of_declaration(file, decl), + } + } + /// `reportMergeSymbolError`: reports `code` at every declaration of both symbols, with related information for the declarations /// of the other symbol. Skips a symbol whose first declaration is in a plain JavaScript file. `named`: the symbol whose name is /// printed. @@ -300,11 +301,11 @@ impl Checker<'_, '_> { } for &(of, decl, _) in symbol { if of == file - && let Some(start) = self.declaration_name_start(of, decl) + && let Some((_, start, _)) = self.place_of_merged_declaration(of, decl) { let others = other .iter() - .filter_map(|d| self.place_of_declaration(d.0, d.1)) + .filter_map(|d| self.place_of_merged_declaration(d.0, d.1)) .collect::>() .into_iter(); let end = match decl { @@ -398,9 +399,11 @@ impl Checker<'_, '_> { let source = files.canonical(refused.source); if refused.target_flags.contains(SymFlags::NAMESPACE_MODULE) { // A value that merges with a non-instantiated namespace reports TS2649 once, on its first declaration. - if let Some(&(of, decl, _)) = added.first() + // "Do not report an error when merging `var globalThis` with the built-in `globalThis`" + if refused.target != files.global_this_symbol + && let Some(&(of, decl, _)) = added.first() && of == file - && let Some(start) = self.declaration_name_start(of, decl) + && let Some((_, start, _)) = self.place_of_merged_declaration(of, decl) { self.error_at((file, start, 0), 2649, &[Arg::Sym(target)]); } @@ -640,19 +643,7 @@ impl Checker<'_, '_> { /// `IsExternalModuleAugmentation` pub(super) fn is_external_module_augmentation(&self, file: FileId, m: ModuleId) -> bool { - let (hir, bound) = (self.hir(file), self.bound(file)); - let is_ambient_module = |it: ModuleId| !matches!(hir[it].name, ModuleName::Ident(_)); - let parent = |it: ModuleId| bound.stmt_parent.get(hir[it].stmt.idx()); - is_ambient_module(m) - && match parent(m) { - Some(Parent::File) => hir.has_module_syntax, - Some(&Parent::Module(around)) => { - is_ambient_module(around) - && matches!(parent(around), Some(Parent::File)) - && !hir.has_module_syntax - } - _ => false, - } + self.files().is_external_module_augmentation(file, m) } /// Whether `checkExternalModuleExports` is called for `module` no later than `file` is @@ -706,18 +697,21 @@ impl Checker<'_, '_> { && self.reports_semantic_errors(visited) } - /// For the members of each class, interface and type literal. `check_class_like_declaration` - /// calls `check_object_type_for_duplicate_declarations` for a class. + /// `report_conflicts_of_late_bound_members` for each class, interface and type literal whose + /// members something has asked for. fn check_duplicate_members(&mut self, file: FileId) { let (hir, bound) = (self.hir(file), self.bound(file)); let unchecked = self.unchecked_jsdoc_types(file); - let classes = hir.classes.iter().map(|class| (class.members, true)); - let interfaces = hir.interfaces.iter().map(|it| (it.members, false)); + let classes = hir.classes.iter().map(|class| class.members); + let interfaces = hir.interfaces.iter().map(|it| it.members); let literals = hir.types.iter().filter_map(|node| match node.kind { - TypeNodeKind::Object(members) if !unchecked.contain(node.pos) => Some((members, false)), + TypeNodeKind::Object(members) if !unchecked.contain(node.pos) => Some(members), _ => None, }); - for (members, is_class) in classes.chain(interfaces).chain(literals) { + for members in classes.chain(interfaces).chain(literals) { + if members.is_empty() || self.is_never_checked(hir[members.at(0)].name_pos) { + continue; + } // Another declaration of the container may have the late-bound member. for is_static in [false, true] { let parent = members.iter().find_map(|m| { @@ -729,13 +723,6 @@ impl Checker<'_, '_> { self.report_conflicts_of_late_bound_members(file, container, is_static); } } - // A single member has nothing to conflict with, unless it is static like the - // `prototype` of a class. - let has_static = members.iter().any(|m| hir[m].flags.contains(Flags::STATIC)); - if !is_class && (members.len() > 1 || has_static) { - let node = hir.parent(hir.node(members.at(0))); - self.check_object_type_for_duplicate_declarations(file, node, members, false); - } } } @@ -799,6 +786,14 @@ impl Checker<'_, '_> { check_private_names: bool, ) { let hir = self.hir(file); + // FOR SPEED. A single member of an interface or a type literal has nothing to conflict + // with, unless it is static like the `prototype` of a class. + if !check_private_names + && members.len() < 2 + && !members.iter().any(|m| hir[m].flags.contains(Flags::STATIC)) + { + return; + } // `instanceNames`, `staticNames`: 1 for a property, 2 for an accessor, 3 once errors have been reported. let mut names: SmallVec<[(Atom, bool, u8); 4]> = SmallVec::new(); // 1 for an instance member, 2 for a static member. @@ -900,6 +895,8 @@ impl Checker<'_, '_> { let first = declarations.first().copied(); let first = first.and_then(|(of, first)| self.place_of_declaration(of, first)); let (of, from, to) = first.unwrap_or(place); + // `GetTextOfNode` does not skip the `*` before the name. + let from = super::spans::start_of_error_range(self.hir(of), from, to); let text = Arg::Bytes(&self.hir(of).text[from as usize..to as usize]); self.error_at(place, code, &[text]); } diff --git a/src/sema/check/errors_emit_helpers.rs b/src/sema/check/errors_emit_helpers.rs index 2b4c67001b63..546a58b8e28c 100644 --- a/src/sema/check/errors_emit_helpers.rs +++ b/src/sema/check/errors_emit_helpers.rs @@ -8,10 +8,10 @@ //! //! A file requests each helper once, where `checkSourceFile` first reaches syntax that needs it. So //! the requesting positions are collected and sorted in the order it visits them: source order, -//! except for nodes that `checkNodeDeferred` defers until everything else is checked. A class -//! expression that is checked early, because its type is requested, is placed where that happened -//! (`check_class_expression_external_helpers`). Any other expression is handled in its regular -//! order. +//! except for nodes that `checkNodeDeferred` defers until everything else is checked. An expression +//! that is checked early, because a type is requested, is placed where that happened +//! (`note_external_emit_helpers_check`). If that was in the check of an earlier file, the task of +//! that file reports (`check_external_emit_helpers_of_later_files`). use super::sink::held; use super::*; @@ -72,12 +72,44 @@ fn helper_names(helper: u32, legacy_decorators: bool) -> &'static [&'static str] /// A call of `checkExternalEmitHelpers`. #[derive(Copy, Clone)] struct Request { - /// The number of deferrals on the way to it, and its position in the file. - order: (u32, u32), + /// The number of deferrals on the way to it, and its position in the file. For an expression + /// that is checked early those of the node that was being checked, and its rank among such + /// expressions, from 1. + order: (u32, u32, u32), /// `GetErrorRangeForNode` of the location. start: u32, end: u32, helpers: u32, + /// The expression whose check makes it (`note_external_emit_helpers_check`). `NONE`: the check + /// of something else, which only `checkSourceFile` of the file comes to. + expression: ExprId, +} + +/// A diagnostic of `checkExternalEmitHelpers` in `file`, which the check of an earlier file, the one +/// with `rank`, has reported at `start`. +pub(super) struct EarlierEmitHelperError { + pub(super) file: FileId, + pub(super) code: u32, + pub(super) args: super::sink::Args, + pub(super) rank: u32, + pub(super) start: u32, +} + +/// `Request::order` of the request that the check of `expression` makes. `regular`: the number of +/// deferrals on the way to it, and its position. `checked`: `Checker::emit_helpers_checked_early`. +fn order_of_expression( + expression: (FileId, ExprId), + regular: (u32, u32), + checked: &[(FileId, ExprId, (u32, u32))], +) -> (u32, u32, u32) { + let regular = (regular.0, regular.1, 0); + match checked.iter().position(|it| (it.0, it.1) == expression) { + Some(rank) => { + let (deferred, start) = checked[rank].2; + regular.min((deferred, start, rank as u32 + 1)) + } + None => regular, + } } /// `AllAccessorDeclarations`, without `GetAccessor`, which nothing here reads. @@ -89,25 +121,91 @@ struct AllAccessorDeclarations { impl Checker<'_, '_> { pub(super) fn check_external_emit_helpers(&mut self, file: FileId) { - let checked = std::mem::take(&mut self.checked_class_expressions); + let checked = std::mem::take(&mut self.emit_helpers_checked_early); + if !self.files().options.import_helpers { + return; + } + self.check_external_emit_helpers_of_later_files(file); + if self.emit_helpers_is_effective_external_module(file) { + let mut requests = self.emit_helpers_requests(file, &checked); + requests.sort_by_key(|request| request.order); + self.emit_helpers_check_requests(file, requests); + } + } + + /// `IsEffectiveExternalModule`. All of a declaration file is ambient. + fn emit_helpers_is_effective_external_module(&self, file: FileId) -> bool { let files = self.files(); let (options, module) = (&files.options, files.module(file)); - // `IsEffectiveExternalModule`. All of a declaration file is ambient. let is_commonjs_module = module.is_commonjs() && (options.module == ModuleKind::CommonJs || options.module.is_node()); - if !options.import_helpers - || module.hir.kind == FileKind::Declaration - || !(module.hir.has_module_syntax || is_commonjs_module) - { - return; + module.hir.kind != FileKind::Declaration + && (module.hir.has_module_syntax || is_commonjs_module) + } + + /// `checkExternalEmitHelpers` where the check of `visited` has come to an expression of a file + /// that is checked later: `requestedExternalEmitHelpers` belongs to the file of the location, + /// so that file does not report the same again. Its task does not see this one: + /// `finish_file` takes back what it has reported instead. + fn check_external_emit_helpers_of_later_files(&mut self, visited: FileId) { + let elsewhere = std::mem::take(&mut self.emit_helpers_checked_elsewhere); + let mut later: Vec = elsewhere.iter().map(|it| it.0).collect(); + later.sort_unstable(); + later.dedup(); + for file in later { + if !self.emit_helpers_is_effective_external_module(file) + || self.emit_helpers_lacks_none(file) + { + continue; + } + // In the order of the checks. + let place = |request: &Request| { + let mut checks = elsewhere.iter(); + checks.position(|&it| it == (file, request.expression)) + }; + let requests = self.emit_helpers_requests(file, &[]).into_iter(); + let mut requests: Vec<(usize, Request)> = requests + .filter_map(|request| Some((place(&request)?, request))) + .collect(); + requests.sort_by_key(|it| (it.0, it.1.order)); + let from = self.reported.len(); + self.emit_helpers_check_requests(file, requests.into_iter().map(|it| it.1).collect()); + let rank = self.files().rank_of_file(visited); + let reported = self.reported[from..].iter().filter(|d| d.file == file); + let reported = reported.map(|d| EarlierEmitHelperError { + file, + code: d.code, + args: d.args.clone(), + rank, + start: d.start, + }); + (self.p.emit_helper_errors_of_earlier_files.lock()).extend(reported); + } + } + + /// FOR SPEED. Whether `checkExternalEmitHelpers` reports nothing in `file`, whatever is asked + /// for: its `tslib` has every helper. + fn emit_helpers_lacks_none(&mut self, file: FileId) -> bool { + let files = self.files(); + let mode = files.module(file).default_mode; + match files.module_of_specifier_as(file, known::tslib, mode) { + Some(helpers_module) => (0..u32::BITS).all(|bit| { + self.emit_helpers_errors_of(helpers_module, 1 << bit) + .is_empty() + }), + None => false, } - let mut requests = self.emit_helpers_requests(file, &checked); - requests.sort_by_key(|request| request.order); + } + + /// `checkExternalEmitHelpers` for each of `requests` of `file`, in that order. Nothing has been + /// requested before. + fn emit_helpers_check_requests(&mut self, file: FileId, requests: Vec) { + let hir = self.hir(file); // `externalHelpersModule`, `requestedExternalEmitHelpers` let (mut resolved, mut requested) = (None, 0); for request in requests { // `checkWithStatement` does not check the body. - if module.hir.is_in_with(request.start) { + if hir.is_in_with(request.start) { continue; } let found = *resolved @@ -119,38 +217,45 @@ impl Checker<'_, '_> { requested |= request.helpers; let helpers = (0..u32::BITS).map(|bit| 1u32 << bit); for helper in helpers.filter(|&helper| unchecked & helper != 0) { - for &name in helper_names(helper, options.experimental_decorators) { - let symbol = files - .atoms - .lookup(name.as_bytes()) - .and_then(|name| files.module_export(helpers_module, name)) - .filter(|&symbol| files.means(symbol, SymFlags::VALUE)); - let mut args = vec![TSLIB.as_bytes().to_vec(), name.as_bytes().to_vec()]; - let code = match symbol { - None => 2343, - Some(symbol) => { - let arity = match helper { - CLASS_PRIVATE_FIELD_GET => 3, - CLASS_PRIVATE_FIELD_SET => 4, - _ => continue, - }; - if self - .emit_helpers_has_signature_with_arity_greater_than(symbol, arity) - { - continue; - } - args.push(super::sink::number_text(arity + 1)); - 2807 - } - }; - self.add_diagnostic(Reported::new( - (file, request.start, request.end), - code, - held(args), - )); + for (code, args) in self.emit_helpers_errors_of(helpers_module, helper) { + let at = (file, request.start, request.end); + self.add_diagnostic(Reported::new(at, code, held(args))); + } + } + } + } + + /// What `checkExternalEmitHelpers` reports where `helper` is first asked of `helpers_module`: + /// the codes and the arguments. + fn emit_helpers_errors_of( + &mut self, + helpers_module: Sym, + helper: u32, + ) -> Vec<(u32, Vec>)> { + let files = self.files(); + let mut errors = Vec::new(); + for &name in helper_names(helper, files.options.experimental_decorators) { + let symbol = files + .atoms + .lookup(name.as_bytes()) + .and_then(|name| files.module_export(helpers_module, name)) + .filter(|&symbol| files.means(symbol, SymFlags::VALUE)); + let arity = match (symbol, helper) { + (None, _) => None, + (Some(_), CLASS_PRIVATE_FIELD_GET) => Some(3), + (Some(_), CLASS_PRIVATE_FIELD_SET) => Some(4), + (Some(_), _) => continue, + }; + let mut args = vec![TSLIB.as_bytes().to_vec(), name.as_bytes().to_vec()]; + if let (Some(symbol), Some(arity)) = (symbol, arity) { + if self.emit_helpers_has_signature_with_arity_greater_than(symbol, arity) { + continue; } + args.push(super::sink::number_text(arity + 1)); } + errors.push((if arity.is_some() { 2807 } else { 2343 }, args)); } + errors } /// `resolveHelpersModule` @@ -217,11 +322,11 @@ impl Checker<'_, '_> { // ───────────────────────────── who asks ───────────────────────────── - /// `checked`: `Checker::checked_class_expressions` + /// `checked`, here and below: `Checker::emit_helpers_checked_early` fn emit_helpers_requests( &mut self, file: FileId, - checked: &[(FileId, ExprId, Option)], + checked: &[(FileId, ExprId, (u32, u32))], ) -> Vec { // `GetEmitScriptTarget` let target = match self.files().options.target { @@ -230,20 +335,19 @@ impl Checker<'_, '_> { }; let index = self.exprs_by_kind(file); let mut requests = Vec::new(); - self.emit_helpers_of_async_functions(file, target, &index, &mut requests); + self.emit_helpers_of_async_functions(file, target, &index, checked, &mut requests); self.emit_helpers_of_statements(file, target, &mut requests); - self.emit_helpers_of_rest_elements(file, target, &index, &mut requests); + self.emit_helpers_of_rest_elements(file, target, &index, checked, &mut requests); self.emit_helpers_of_decorators(file, target, &mut requests); self.emit_helpers_of_class_expressions(file, target, checked, &mut requests); - self.emit_helpers_of_private_names(file, target, &index, &mut requests); + self.emit_helpers_of_private_names(file, target, &index, checked, &mut requests); requests } /// The number of times `checkNodeDeferred` defers a direct child of `at`. Deferred are the body /// of a function expression, of an arrow function and of a method of an object literal, the /// whole of an accessor of an object literal, the members of a class expression, the operand of - /// `void`, and the contents of a JSX element. `None`: it is ambient (`NodeFlagsAmbient`), or - /// it is in a type literal. + /// `void`, and the contents of a JSX element. `None`: it is ambient (`NodeFlagsAmbient`). fn emit_helpers_span(&self, file: FileId, mut at: Parent) -> Option { let (hir, bound) = (self.hir(file), self.bound(file)); let mut deferred = 0; @@ -266,9 +370,16 @@ impl Checker<'_, '_> { if hir[m].flags.contains(Flags::AMBIENT) { return None; } - let MemberOwner::Class(class) = bound.member_owner[m.idx()] else { - at = self.parent_of_node(file, Parent::MemberInit(m)); - continue; + let class = match bound.member_owner[m.idx()] { + MemberOwner::Class(class) => class, + MemberOwner::TypeLiteral(t) => { + at = self.emit_helpers_out_of_type(file, t, &mut deferred)?; + continue; + } + _ => { + at = self.parent_of_node(file, Parent::MemberInit(m)); + continue; + } }; if let ClassOwner::Expr(_) = bound.class_owner[class.idx()] { deferred += 1; @@ -329,16 +440,36 @@ impl Checker<'_, '_> { } FnOwner::Stmt(s) => Some(Parent::Stmt(s)), FnOwner::Member(m) => Some(Parent::MemberInit(m)), - _ => None, + FnOwner::Type(t) => self.emit_helpers_out_of_type(file, t, deferred), + FnOwner::None => None, } } + /// `emit_helpers_span`, one step: out of the type node `t`. + fn emit_helpers_out_of_type( + &self, + file: FileId, + t: TypeNodeId, + deferred: &mut u32, + ) -> Option { + let hir = self.hir(file); + let (around, inside) = Self::emit_helpers_source_element(hir, hir.node(t)); + let Parent::FnBody(f) = inside else { + return Some(inside); + }; + // `checkSignatureDeclaration` checks the type parameters and the return type. + let below = hir.find_ancestor(hir.node(t), |n| hir.parent(n) == around); + let is_head = matches!(hir.data(below), NodeData::Type(_) | NodeData::TypeParam(_)); + self.emit_helpers_out_of_fn(file, f, is_head, deferred) + } + /// `checkSignatureDeclaration`, `checkYieldExpression` fn emit_helpers_of_async_functions( &self, file: FileId, target: ScriptTarget, index: &ExprsByKind, + checked: &[(FileId, ExprId, (u32, u32))], requests: &mut Vec, ) { if target >= ScriptTarget::ES2018 { @@ -373,10 +504,11 @@ impl Checker<'_, '_> { }; let (start, end) = self.error_range_of_fn(file, f); requests.push(Request { - order: (place + deferred, start), + order: (place + deferred, start, 0), start, end, helpers, + expression: ExprId::NONE, }); } for &e in index.of(ExprTag::Yield) { @@ -388,10 +520,11 @@ impl Checker<'_, '_> { { let start = self.error_start_inside_parentheses(file, e); requests.push(Request { - order: (deferred, start), + order: order_of_expression((file, e), (deferred, start), checked), start, end: self.error_end_inside_parentheses(file, e), helpers: AWAIT | ASYNC_DELEGATOR | ASYNC_VALUES, + expression: e, }); } } @@ -419,16 +552,17 @@ impl Checker<'_, '_> { let is_module_element = is_commonjs && around == Parent::File; let mut ask = |deferred: u32, (start, end): (u32, u32), helpers: u32| { requests.push(Request { - order: (deferred, stmt.start), + order: (deferred, stmt.start, 0), start, end, helpers, + expression: ExprId::NONE, }); }; match stmt.kind { StmtKind::Import(x) if is_module_element => { let import = hir[x]; - if !self.emit_helpers_import_clause_is_checked(file, s, &import) { + if !self.emit_helpers_import_clause_is_checked(file, s, x) { continue; } let whole = (stmt.start, self.end_of_stmt(file, s)); @@ -540,29 +674,15 @@ impl Checker<'_, '_> { &self, file: FileId, s: StmtId, - import: &Import, + import: ImportId, ) -> bool { let hir = self.hir(file); - if import.spec.is_none() || !self.emit_helpers_has_only_string_attributes(file, s) { + if hir[import].spec.is_none() || !self.emit_helpers_has_only_string_attributes(file, s) { return false; } // `grammarErrorOnNode` reports nothing in a file with parse errors, and then no check bails // out. - if has_parse_diagnostics(hir) { - return true; - } - if import.type_only { - let has_bindings = import.namespace.is_some() || !import.named.is_empty(); - return !(import.default.is_some() && has_bindings) - && !import.named.iter().any(|spec| hir[spec].type_only); - } - !import.is_deferred - || import.default.is_none() - && import.namespace.is_some() - && matches!( - self.files().options.module, - ModuleKind::EsNext | ModuleKind::Preserve - ) + has_parse_diagnostics(hir) || self.grammar_error_of_import_clause(file, import).is_none() } /// `checkExternalImportOrExportDeclaration`: every import attribute of the statement `s` is given as a string literal. @@ -599,6 +719,7 @@ impl Checker<'_, '_> { file: FileId, target: ScriptTarget, index: &ExprsByKind, + checked: &[(FileId, ExprId, (u32, u32))], requests: &mut Vec, ) { if target >= ScriptTarget::ES2018 { @@ -607,16 +728,21 @@ impl Checker<'_, '_> { let (hir, bound) = (self.hir(file), self.bound(file)); for (i, element) in hir.pat_props.iter().enumerate() { let p = PatPropId(i as u32); + // `renamedBindingElementsInTypes`: `checkVariableLikeDeclaration` returns before. if element.is_rest + && !(self.is_renamed_binding_element(file, p) + && self.returns_before_type_of_symbol(file, element.value)) + && !hir.is_ambient(hir.node(p)) && let Some(deferred) = self .emit_helpers_span(file, self.parent_of_node(file, Parent::PatPropDefault(p))) { let (start, end) = self.error_range_of_pat_prop(file, p); requests.push(Request { - order: (deferred, start), + order: (deferred, start, 0), start, end, helpers: REST, + expression: ExprId::NONE, }); } } @@ -640,10 +766,11 @@ impl Checker<'_, '_> { let dots_end = self.end_of_token_before(file, self.start_of(file, last.value)); let start = dots_end.saturating_sub(3); requests.push(Request { - order: (deferred, start), + order: order_of_expression((file, e), (deferred, start), checked), start, end: self.end_of_expr(file, last.value), helpers: REST, + expression: e, }); } } @@ -757,11 +884,19 @@ impl Checker<'_, '_> { continue; } let (start, end) = self.emit_helpers_range_of_decorator(file, e); + // `checkDecorators(node)` comes before anything else that the check of `node` asks for, + // and modifiers can precede the first decorator. + let node = match owner { + DecoratorOwner::Class(class) => hir.node(class), + DecoratorOwner::Member(m) => hir.node(m), + DecoratorOwner::Param(p) => hir.node(p), + }; requests.push(Request { - order: (deferred, start), + order: (deferred, start.min(hir.start(node)), 0), start, end, helpers, + expression: ExprId::NONE, }); } } @@ -900,22 +1035,40 @@ impl Checker<'_, '_> { None } + /// `checkExternalEmitHelpers`, where the check of the expression `node` calls it: notes when + /// that is, if it is before the regular order of `node`. `emit_helpers_requests` makes the + /// request. + pub(super) fn note_external_emit_helpers_check(&mut self, file: FileId, node: ExprId) { + if self.files().options.import_helpers + && !self.is_type_checked + && let Some(visited) = self.task.file + && visited != file + && self.emit_helpers_checked_elsewhere.last() != Some(&(file, node)) + && self.is_checked_no_later_than(visited, file) + { + self.emit_helpers_checked_elsewhere.push((file, node)); + } + if self.files().options.import_helpers + && self.task.file == Some(file) + && !self.is_type_checked + && let current = self.current_source_element + && let Some(order) = self.emit_helpers_order_of_early_check(file, node, current) + && !(self.emit_helpers_checked_early.iter()).any(|it| (it.0, it.1) == (file, node)) + { + self.emit_helpers_checked_early.push((file, node, order)); + } + } + /// `checkClassExpressionExternalHelpers`, where `checkClassExpression` calls it for `node`, - /// which is `class`: notes when that is. `emit_helpers_of_class_expressions` makes the request. + /// which is `class`. `emit_helpers_of_class_expressions` has the conditions. pub(super) fn check_class_expression_external_helpers( &mut self, file: FileId, node: ExprId, class: ClassId, ) { - if self.files().options.import_helpers - && self.task.file == Some(file) - && !self.is_type_checked - && self.hir(file)[class].name.is_none() - && !(self.checked_class_expressions.iter()).any(|it| (it.0, it.1) == (file, node)) - { - let current = self.current_source_element; - self.checked_class_expressions.push((file, node, current)); + if self.hir(file)[class].name.is_none() { + self.note_external_emit_helpers_check(file, node); } } @@ -933,12 +1086,29 @@ impl Checker<'_, '_> { let node = match current { // `checkSourceFile` has not begun. None => return Some((0, 0)), + // `checkExpressionEx` has set it: an assignment is never deferred. + Some(CurrentNode::Expr(of, x)) + if of == file && matches!(hir[x].kind, ExprKind::Assign { .. }) => + { + Self::emit_helpers_source_element(hir, hir.node(x)).0 + } Some(CurrentNode::Expr(of, x)) if of == file => hir.node(x), Some(CurrentNode::TypeNode(of, t)) if of == file => hir.node(t), Some(CurrentNode::Node(of, node)) if of == file => node, Some(_) => return None, }; - // Of the nodes that the two are called with, those that can contain an expression. + if Self::emit_helpers_source_element(hir, hir.parent(hir.node(e))).0 == node { + return None; + } + let (_, inside) = Self::emit_helpers_source_element(hir, node); + // Nothing is deferred in an ambient context. + let deferred = self.emit_helpers_span(file, inside).unwrap_or(0); + Some((deferred, hir.start(node))) + } + + /// The innermost node, `node` or around it, that `checkSourceElement` or `checkDeferredNode` is + /// called with and that can contain an expression, and the `Parent` of what is directly in it. + fn emit_helpers_source_element(hir: &hir::File, node: Node) -> (Node, Parent) { let is_source_element = |n: Node| match hir.data(n) { NodeData::Stmt(_) | NodeData::VarDecl(_) @@ -959,9 +1129,6 @@ impl Checker<'_, '_> { ), _ => false, }; - if hir.find_ancestor(hir.parent(hir.node(e)), is_source_element) == node { - return None; - } let around = hir.find_ancestor(node, is_source_element); let inside = match hir.data(around) { NodeData::Stmt(s) => Parent::Stmt(s), @@ -981,24 +1148,20 @@ impl Checker<'_, '_> { }, _ => Parent::File, }; - // Nothing is deferred in an ambient context. - let deferred = self.emit_helpers_span(file, inside).unwrap_or(0); - Some((deferred, hir.start(node))) + (around, inside) } - /// `checkClassExpressionExternalHelpers`. `checked`: `Checker::checked_class_expressions`. + /// `checkClassExpressionExternalHelpers` fn emit_helpers_of_class_expressions( &self, file: FileId, target: ScriptTarget, - checked: &[(FileId, ExprId, Option)], + checked: &[(FileId, ExprId, (u32, u32))], requests: &mut Vec, ) { let (hir, bound, files) = (self.hir(file), self.bound(file), self.files()); let is_identifier = |pat: PatId| matches!(hir[pat].kind, PatKind::Ident(_)); let is_computed_name_at = |pos: u32| hir.text.get(pos as usize) == Some(&b'['); - // Each with its rank in the order in which `checkClassExpression` came to them. - let mut found: Vec<(usize, Request)> = Vec::new(); for (i, class) in hir.classes.iter().enumerate() { let ClassOwner::Expr(e) = bound.class_owner[i] else { continue; @@ -1094,36 +1257,19 @@ impl Checker<'_, '_> { let Some((start, end)) = location else { continue; }; - let noted = checked.iter().position(|it| (it.0, it.1) == (file, e)); - // The check of an earlier file has come to it. - let (rank, order) = if self.p.deferred_nodes.get(&self.task, &(file, e)).is_some() { - (0, (0, 0)) - } else { - let early = noted - .and_then(|at| self.emit_helpers_order_of_early_check(file, e, checked[at].2)); - ( - noted.map_or(usize::MAX, |at| at + 1), - early.unwrap_or((deferred, class.name_pos)), - ) - }; let helpers = if has_computed_name { SET_FUNCTION_NAME | PROP_KEY } else { SET_FUNCTION_NAME }; - found.push(( - rank, - Request { - order, - start, - end, - helpers, - }, - )); + requests.push(Request { + order: order_of_expression((file, e), (deferred, class.name_pos), checked), + start, + end, + helpers, + expression: e, + }); } - // The sort by `order` is stable. - found.sort_by_key(|it| it.0); - requests.extend(found.into_iter().map(|it| it.1)); } /// `checkPropertyAccessExpressionOrQualifiedName`, `checkInExpression` @@ -1132,6 +1278,7 @@ impl Checker<'_, '_> { file: FileId, target: ScriptTarget, index: &ExprsByKind, + checked: &[(FileId, ExprId, (u32, u32))], requests: &mut Vec, ) { if target >= ScriptTarget::ESNext && self.files().options.use_define_for_class_fields { @@ -1150,7 +1297,7 @@ impl Checker<'_, '_> { }; let start = self.start_inside_parentheses(file, e); requests.push(Request { - order: (deferred, start), + order: order_of_expression((file, e), (deferred, start), checked), start, end: self.end_inside_parentheses(file, e), helpers: match bound.get_assignment_target_kind(hir, e) { @@ -1158,6 +1305,7 @@ impl Checker<'_, '_> { AssignmentKind::Definite => CLASS_PRIVATE_FIELD_SET, AssignmentKind::Compound => CLASS_PRIVATE_FIELD_SET | CLASS_PRIVATE_FIELD_GET, }, + expression: e, }); } for &e in index.of(ExprTag::Binary) { @@ -1175,10 +1323,11 @@ impl Checker<'_, '_> { && let Some(deferred) = self.emit_helpers_span(file, bound.expr_parent[e.idx()]) { requests.push(Request { - order: (deferred, start), + order: order_of_expression((file, left), (deferred, start), checked), start, end: self.end_of_name_at(file, start), helpers: CLASS_PRIVATE_FIELD_IN, + expression: left, }); } } diff --git a/src/sema/check/errors_enums_names.rs b/src/sema/check/errors_enums_names.rs index d4ff2795fac6..cfb3248143cf 100644 --- a/src/sema/check/errors_enums_names.rs +++ b/src/sema/check/errors_enums_names.rs @@ -52,8 +52,8 @@ impl Checker<'_, '_> { // ───────────────────────────── `const` enums ───────────────────────────── - /// `checkConstEnumAccess` for `e` and for each parenthesized expression around it, which has - /// the same type. + /// `checkConstEnumAccess` for `e` and for each parenthesized expression and `JsxExpression` + /// around it, which have the same type. pub(super) fn check_const_enum_access(&mut self, file: FileId, e: ExprId, ty: TypeId) { let (hir, files) = (self.hir(file), self.files()); let TypeData::Anon { @@ -101,7 +101,10 @@ impl Checker<'_, '_> { { self.error(file, node, 2748, &[Arg::Bytes(flag_name)]); } - if hir.kind(parent) != Kind::ParenthesizedExpression { + if !matches!( + hir.kind(parent), + Kind::ParenthesizedExpression | Kind::JsxExpression + ) { break; } node = parent; @@ -122,6 +125,14 @@ impl Checker<'_, '_> { if !files.module(file).is_module() && let Some(symbol) = bound.lookup(bound.scopes[0].locals, known::globalThis) { + // The table has a placeholder for a symbol that `mergeSymbol` has refused + // (`Files::redirect_name_to`). + let is_local = + |part: &&Sym| part.file == file && bound.symbols[part.id.idx()].parent.is_none(); + let refused = files.refused_merges.iter(); + let refused = refused.filter(|it| it.target == files.global_this_symbol); + let refused = refused.flat_map(|it| it.source_parts).find(is_local); + let symbol = refused.map_or(symbol, |part| part.id); for &decl in bound.symbols[symbol.idx()].decls.iter() { report(self, decl, known::globalThis); } @@ -252,6 +263,7 @@ impl Checker<'_, '_> { for &(e, scope) in &bound.free_idents { if let ExprKind::Ident(name) = hir[e].kind && !bound.is_unchecked(e.idx()) + && !hir.is_in_jsdoc(hir[e].pos) && resolves_to_umd_global(files, file, scope, name, SymFlags::VALUE) { self.error_at((file, hir[e].pos, 0), 2686, &[Arg::Atom(name)]); @@ -271,7 +283,7 @@ impl Checker<'_, '_> { // `getJsxNamespaceContainerForImplicitImport` let path = files.module(file).file_name(); let implicit_import = crate::program::jsx_runtime_of(options, hir, &files.atoms) - .filter(|_| path.ends_with(b".tsx") || path.ends_with(b".jsx")) + .filter(|_| crate::resolve::is_jsx_file_name(path)) .and_then(|spec| files.module_of_specifier(file, self.atoms().intern(&spec))); if implicit_import.is_some() { return; @@ -349,7 +361,9 @@ impl Checker<'_, '_> { return; } let name = files.symbol(result).name; - if resolves_to_umd_global(files, file, scope, name, meaning) { + if !hir.is_in_jsdoc(hir.start(error_location)) + && resolves_to_umd_global(files, file, scope, name, meaning) + { self.error(file, error_location, 2686, &[Arg::Atom(name)]); } let associated_declaration = @@ -379,6 +393,15 @@ impl Location { } } } + + /// `hir`: of `file()`. + pub(super) fn node(self, hir: &hir::File) -> Node { + match self { + Location::Member(_, member) => hir.node(member), + Location::Variable(_, d) => hir.node(d), + Location::Expr(_, e) => hir.node(e), + } + } } pub(super) fn is_ambient_enum(hir: &hir::File, en: EnumId) -> bool { @@ -390,17 +413,13 @@ pub(super) fn is_ambient_enum(hir: &hir::File, en: EnumId) -> bool { /// `isBlockScopedNameDeclaredBeforeUse` pub(super) fn is_declared_before_use( c: &mut Checker<'_, '_>, - declaration: Location, + (of, declaration): (FileId, Node), usage: Location, ) -> bool { - let (file, node) = (usage.file(), |location: Location| match location { - Location::Member(file, member) => c.hir(file).node(member), - Location::Variable(file, d) => c.hir(file).node(d), - Location::Expr(file, e) => c.hir(file).node(e), - }); - let (declared, used) = (node(declaration), node(usage)); + let file = usage.file(); + let used = usage.node(c.hir(file)); // The order across files is undetermined. - declaration.file() != file || c.is_block_scoped_name_declared_before_use(file, declared, used) + of != file || c.is_block_scoped_name_declared_before_use(file, declaration, used) } // ───────────────────────────── kinds of types and symbols ───────────────────────────── @@ -417,11 +436,10 @@ pub(super) fn resolves_to_umd_global( !files.options.allow_umd_global_access && files.module(file).is_module() && umd_global(files, name).is_some_and(|global| { - // `getSymbol`: an alias is matched by the meaning of its target. - let flags = files.symbol_flags(global); + // `getSymbol`: an alias is matched by the meaning of its target, which is every meaning + // if it cannot be resolved. files.resolve_name(file, scope, name, meaning) == Some(global) - && flags != SymFlags::all() - && flags.intersects(meaning) + && files.symbol_flags(global).intersects(meaning) }) } diff --git a/src/sema/check/errors_grammar.rs b/src/sema/check/errors_grammar.rs index 70477aceec79..1d90cb48d11e 100644 --- a/src/sema/check/errors_grammar.rs +++ b/src/sema/check/errors_grammar.rs @@ -37,6 +37,7 @@ impl Checker<'_, '_> { pub(super) fn check_grammar(&mut self, file: FileId) { self.check_strict_mode(file, !has_parse_diagnostics(self.hir(file))); + self.check_grammar_augments_tags(file); } /// `getSourceFileFromReference`, `processingDiagnostic.toDiagnostic`: the error for the `/// diff --git a/src/sema/check/errors_grammar_modifiers.rs b/src/sema/check/errors_grammar_modifiers.rs index 259adef4ce09..a4c5333c01b3 100644 --- a/src/sema/check/errors_grammar_modifiers.rs +++ b/src/sema/check/errors_grammar_modifiers.rs @@ -165,10 +165,45 @@ impl Checker<'_, '_> { }); } + /// `checkGrammarClassDeclarationHeritageClauses` returns at its first error. The front end + /// reports the `@augments` tags of a class (8023) apart from its clauses: this takes back what + /// the original does not get to. No query may be in progress. + pub(super) fn check_grammar_augments_tags(&mut self, file: FileId) { + let hir = self.hir(file); + for &(class, tag) in hir.unmatched_augments_tags.iter() { + let node = hir.node(class); + let body = match hir[class].members.iter().next() { + Some(first) => hir[first].loc.pos, + None => self.end_of_node(file, node), + }; + let (clauses, extends) = (hir.start(node)..body, hir[hir[class].extends].pos); + // It reads the tags once the first `extends` clause has passed 1172, 1173 and 1174. + let returns_before = self.reported.iter().any(|d| { + d.file == file + && clauses.contains(&d.start) + && (matches!(d.code, 1173 | 1174) || d.code == 1175 && d.start < extends) + }); + if returns_before || self.grammar_error_in_modifiers(file, class).is_some() { + self.reported + .retain(|d| d.file != file || d.code != 8023 || d.start != tag); + continue; + } + self.take_back_grammar_errors_of_heritage_clauses(file, node); + // `.. || c.checkGrammarTypeParameterList(..)` + self.reported + .retain(|d| d.file != file || d.code != 1098 || !clauses.contains(&d.start)); + } + } + /// `checkGrammarTypeParameterList`: `<>` after the name of a class, or after `class`. fn check_grammar_type_parameter_list_of_class(&mut self, file: FileId, class: ClassId) -> bool { let hir = self.hir(file); - let (text, name) = (&hir.text[..], hir[class].name_pos as usize); + let text = &hir.text[..]; + let name = match hir[class].modifiers.iter().next_back() { + _ if hir[class].name.is_some() => hir[class].name_pos as usize, + Some(last) => skip_trivia(text, self.end_of_node(file, hir.node(last)) as usize), + None => hir[class].start as usize, + }; let open = skip_trivia(text, name + word_at(text, name).len()); let close = skip_trivia(text, open + 1); text.get(open) == Some(&b'<') @@ -618,7 +653,9 @@ impl Checker<'_, '_> { ) { return error(1242, ["", ""]); } - if !class.is_some_and(|class| hir[class].flags.contains(Flags::ABSTRACT)) { + if !class.is_some_and(|class| hir[class].flags.contains(Flags::ABSTRACT)) + || hir.kind(hir.parent(location)) != Kind::ClassDeclaration + { let is_property = kind == Kind::PropertyDeclaration; return error(if is_property { 1253 } else { 1244 }, ["", ""]); } diff --git a/src/sema/check/errors_heritage.rs b/src/sema/check/errors_heritage.rs index faf371fee58d..7a998552db38 100644 --- a/src/sema/check/errors_heritage.rs +++ b/src/sema/check/errors_heritage.rs @@ -21,7 +21,7 @@ struct IndexConstraints<'a> { ty: TypeId, /// `getIndexInfosOfType(t)` infos: &'a [IndexInfo], - /// The members declared directly in the declarations of `t`. + /// The members declared directly in the declarations of `t.symbol`. locals: &'a [(FileId, Span)], /// `interfaceDeclaration`, for a property and an index signature that come from different base /// interfaces. @@ -53,7 +53,7 @@ impl Checker<'_, '_> { if class.extends.is_some() && let Some(&base) = self.base_types(sym).first() { - match self.unrelated_with_this_argument(class_type, base, this) { + match self.unrelated_with_this_argument(class_type, base, this, false) { Some(with_this) => self.issue_member_specific_error(file, c, with_this, 2415), // The static side is checked only if the instance side has no error. None => { @@ -79,9 +79,13 @@ impl Checker<'_, '_> { if !self.is_valid_base_type(implemented) { continue; } - let is_class = matches!(*self.data(implemented), TypeData::Ref { target, .. } if self.files().flags(target).contains(SymFlags::CLASS)); + let is_class = matches!( + self.symbol_of_type(implemented), + Some(super::errors_small::SymbolAtLocation::Symbol(symbol)) + if self.files().flags(symbol).contains(SymFlags::CLASS) + ); if let Some(with_this) = - self.unrelated_with_this_argument(class_type, implemented, this) + self.unrelated_with_this_argument(class_type, implemented, this, false) { let generic_diag = if is_class { 2720 } else { 2420 }; self.issue_member_specific_error(file, c, with_this, generic_diag); @@ -107,22 +111,28 @@ impl Checker<'_, '_> { members } - /// `isTypeAssignableTo(source, getTypeWithoutSignatures(ty))`. A source is related to an + /// Whether `source` is assignable to `getTypeWithoutSignatures(ty)`. A source is related to an /// intersection if it is related to each member (`typeRelatedToEachType`) and has the - /// properties of the whole (`propertiesRelatedTo`). + /// properties of the whole (`propertiesRelatedTo`). The one run of tsgo has an `errorNode`: + /// `report_static_side`. fn is_assignable_to_type_without_signatures(&mut self, source: TypeId, ty: TypeId) -> bool { if !self.is_intersection(ty) { let target = self.type_without_signatures(ty); - return self.is_assignable(source, target); + return self.is_assignable_on_trial(source, target); } for &member in self.constituents(ty) { let target = self.type_without_signatures(member); - if !self.is_assignable(source, target) { + if !self.is_assignable_on_trial(source, target) { return false; } } let properties = self.type_of_properties(ty); - self.is_assignable(source, properties) + self.is_assignable_on_trial(source, properties) + } + + /// See `try_is_type_related_to`: nothing is reported, and an overflow counts as unrelated. + fn is_assignable_on_trial(&mut self, source: TypeId, target: TypeId) -> bool { + self.try_is_type_related_to(source, target, Relation::Assignable, true) == Ok(true) } /// 2417: `checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), ..)` has @@ -146,7 +156,7 @@ impl Checker<'_, '_> { let mut unrelated = None; if members.len() > 1 { for &member in &members { - if !self.is_assignable(static_type, member.0) { + if !self.is_assignable_on_trial(static_type, member.0) { unrelated = Some(member); break; } @@ -164,6 +174,13 @@ impl Checker<'_, '_> { head, level, ); + // `r.overflow`: that is the diagnostic, about the two types passed in. + if let Some(code @ (2859 | 2321)) = lines.first().map(|line| line.code) { + let types = [Arg::Type(static_type), Arg::Type(printed)]; + let diagnostic = self.new_diagnostic(at, code, &types); + self.add_diagnostic(diagnostic); + return; + } // tsgo's type has the symbol of `shown` and is printed like it. `target` has no symbol. let from = self.type_to_string(target); let to = self.type_names_for_error_display(static_type, shown).1; @@ -287,19 +304,22 @@ impl Checker<'_, '_> { self.synth(shape) } - /// `getTypeWithThisArgument` of `ty` and of `base`, with `this` for both. `None`: the first is assignable to the second. + /// `getTypeWithThisArgument` of `ty` and of `base`, with `this` for both. `None`: the first is + /// assignable to the second. `is_trial`: see `try_is_type_related_to`. If not, this is + /// `checkTypeAssignableTo(typeWithThis, baseWithThis, nil, nil)`. fn unrelated_with_this_argument( &mut self, ty: TypeId, base: TypeId, this: TypeId, + is_trial: bool, ) -> Option<[TypeId; 2]> { // It returns a type that is not a reference unchanged. Deciding that is costly // (`isThislessInterface`), and whether the two are related does not depend on it, so it is // evaluated only once they are found unrelated. let mut with_this = [ty, base].map(|t| self.type_with_this_argument(t, this)); let [source, target] = with_this; - if self.try_is_type_related_to(source, target, Relation::Assignable, true) == Ok(true) { + if self.try_is_type_related_to(source, target, Relation::Assignable, is_trial) == Ok(true) { return None; } for (t, plain) in with_this.iter_mut().zip([ty, base]) { @@ -385,22 +405,41 @@ impl Checker<'_, '_> { declarations } - /// `getTargetSymbol`. `createUnionOrIntersectionProperty` returns `singleProp` where the - /// members of an intersection all have that symbol, or instantiations of it that - /// `compareProperties` finds equal. + /// `singleProp` of `createUnionOrIntersectionProperty`, where the members of an intersection + /// all have that symbol, or instantiations of it that `compareProperties` finds equal. With + /// `mergedInstantiations`: the property is a clone of it, one per intersection. + fn single_prop<'a, 'b>(&mut self, prop: &'a Prop<'b>) -> Option<(&'a Prop<'b>, bool)> { + let PropSource::Intersected(_, parts) = &prop.source else { + return None; + }; + let (single_prop, others) = parts.split_first()?; + if (others.iter()).any(|other| other.source != single_prop.source) { + return None; + } + let ty = self.type_of_prop(single_prop, MapperId::IDENTITY); + if (others.iter()).any(|other| self.type_of_prop(other, MapperId::IDENTITY) != ty) { + return None; + } + let PropSource::Symbol(symbol) = single_prop.source else { + return Some((single_prop, false)); + }; + let is_generic = (self.files().parent_of_symbol(symbol)) + .is_some_and(|parent| !self.local_type_params_of_symbol(parent).is_empty()); + // `prop != singleProp` + let merged_instantiations = is_generic && { + let instantiation = self.instantiation_of_member(symbol, single_prop.mapper); + (others.iter()) + .any(|other| self.instantiation_of_member(symbol, other.mapper) != instantiation) + }; + Some((single_prop, merged_instantiations)) + } + + /// `getTargetSymbol` fn target_symbol<'a>(&mut self, prop: &'a Prop<'a>) -> &'a Prop<'a> { - if let PropSource::Intersected(_, parts) = &prop.source - && let Some((single_prop, others)) = parts.split_first() - && others - .iter() - .all(|other| other.source == single_prop.source) - { - let ty = self.type_of_prop(single_prop, MapperId::IDENTITY); - if (others.iter()).all(|other| self.type_of_prop(other, MapperId::IDENTITY) == ty) { - return self.target_symbol(single_prop); - } + match self.single_prop(prop) { + Some((single_prop, false)) => self.target_symbol(single_prop), + _ => prop, } - prop } /// `prop.Flags&SymbolFlagsClassMember`. It has `SymbolFlagsMethod` for @@ -426,6 +465,9 @@ impl Checker<'_, '_> { PropSource::Copy(_, of, true) => self.kinds_of_prop(&of[0]), // `createUnionOrIntersectionProperty`: `propFlags` and `syntheticFlag`. PropSource::Intersected(_, parts) => { + if let Some((single_prop, _)) = self.single_prop(prop) { + return self.kinds_of_prop(single_prop); + } let (mut flags, mut is_method) = (SymFlags::empty(), true); for part in parts.iter() { let of_part = self.kinds_of_prop(part); @@ -455,13 +497,15 @@ impl Checker<'_, '_> { base_declaration_flags: Flags, ) -> bool { let declarations = self.declarations_of_prop(base); + // `CheckFlagsSynthetic` + let is_synthetic = + matches!(base.source, PropSource::Intersected(..)) && self.single_prop(base).is_none(); let is_abstract_or_interface = |&declaration: &(FileId, Decl)| { self.is_property_abstract_or_interface(declaration, base_declaration_flags) }; - // `CheckFlagsSynthetic` - match base.source { - PropSource::Intersected(..) => declarations.iter().any(is_abstract_or_interface), - _ => declarations.iter().all(is_abstract_or_interface), + match is_synthetic { + true => declarations.iter().any(is_abstract_or_interface), + false => declarations.iter().all(is_abstract_or_interface), } } @@ -503,8 +547,7 @@ impl Checker<'_, '_> { let mut missed_properties: Vec<&Prop> = Vec::new(); 'base_property_check: for base_property in &base_members.shape().props { let base = self.target_symbol(base_property); - // `SymbolFlagsPrototype` - if base.name == known::prototype && matches!(base.source, PropSource::Type(_)) { + if self.is_prototype_of_class(base) { continue; } let Some(derived) = own_members.resolved.prop(base.name) else { @@ -670,10 +713,16 @@ impl Checker<'_, '_> { let Some(&(of, uninitialized)) = uninitialized else { return false; }; - // `SymbolFlagsTransient`: `lateBindMember` created the symbol. - if members.iter().any(|&(f, m)| { - matches!(self.hir(f)[m].key, PropKey::Computed(name) if is_dynamic_name(self.hir(f), name)) - }) || (declarations.iter()).any(|&(f, d)| self.hir(f).is_ambient(self.hir(f).node(d))) + // `SymbolFlagsTransient`: the checker created the symbol. `cloneSymbol` sets the flag, and + // `lateBindMember` created the symbol of a dynamic name. + let PropSource::Symbol(symbol) = derived.source else { + return false; + }; + if self.files().flags(symbol).contains(SymFlags::TRANSIENT) + || members.iter().any(|&(f, m)| { + matches!(self.hir(f)[m].key, PropKey::Computed(name) if is_dynamic_name(self.hir(f), name)) + }) + || (declarations.iter()).any(|&(f, d)| self.hir(f).is_ambient(self.hir(f).node(d))) { return false; } @@ -691,7 +740,12 @@ impl Checker<'_, '_> { }; member.flags.contains(Flags::DEFINITE) || !self.p.files.options.strict_null_checks - || !self.is_assigned_in_constructor(file, hir[constructor].func, name, class_type) + || !self.is_assigned_in_constructor( + file, + hir[constructor].func, + super::flow::AccessKey::Name(name), + class_type, + ) } pub(super) fn check_interface_heritage(&mut self, file: FileId, i: InterfaceId) { @@ -730,14 +784,14 @@ impl Checker<'_, '_> { if !self.check_inherited_properties_are_identical(sym, ty, &bases, Some(at)) { return; } - let this = self.intern(TypeData::ThisParam(sym)); for &base in bases.iter() { // `resolveBaseTypesOfInterface`: a type that cannot be extended is not a base type. if !self.is_valid_base_type(base) { continue; } + let this = self.this_argument_for_base_type(sym, base); if let Some([type_with_this, base_with_this]) = - self.unrelated_with_this_argument(ty, base, this) + self.unrelated_with_this_argument(ty, base, this, true) { self.check_type_assignable_to( type_with_this, @@ -781,13 +835,13 @@ impl Checker<'_, '_> { let own: Vec = (self.resolve_declared_members(sym).props.iter()) .map(|prop| prop.name) .collect(); - let this = self.intern(TypeData::ThisParam(sym)); let access = PropFlags::PRIVATE | PropFlags::PROTECTED; // For a private or protected property, also its declaration. let mut seen: Vec<(Atom, TypeId, PropFlags, Option<&PropSource>, TypeId)> = Vec::new(); let mut identical = true; for &declared_base in bases { // In each base, `this` is instantiated with the `this` type of the derived type. + let this = self.this_argument_for_base_type(sym, declared_base); let base = self.type_with_this_argument(declared_base, this); let Some(members) = self.members(base) else { continue; @@ -865,14 +919,22 @@ impl Checker<'_, '_> { ..*i }) .collect(); + // The static side of a class whose base constructor is a type variable is an intersection. + let is_object = self.is_object_type(ty); let cx = IndexConstraints { file, ty, infos: &infos, - locals, + locals: if is_object { locals } else { &[] }, interface, }; - for prop in &members.shape().props { + // `getPropertiesOfObjectType(t)` + let props: &[Prop] = if is_object { + &members.shape().props[..] + } else { + &[] + }; + for prop in props { if !(is_static && prop.name == known::prototype) { let prop_type = self.type_of_prop_as_read(prop, members.mapper); self.check_index_constraint_for_property(&cx, prop, None, prop_type); @@ -895,7 +957,7 @@ impl Checker<'_, '_> { | MemberKind::Getter | MemberKind::Setter ) - || self.member_name(f, member.key).is_some() + || self.declared_member_name(f, member.key).is_some() { continue; } diff --git a/src/sema/check/errors_implicit.rs b/src/sema/check/errors_implicit.rs index 9ded8ae53443..7cde0dfc1f47 100644 --- a/src/sema/check/errors_implicit.rs +++ b/src/sema/check/errors_implicit.rs @@ -24,14 +24,14 @@ impl Checker<'_, '_> { return; }; let (code, is_the_one_to_be_told) = if decl.kind == FnKind::Setter { - let getter = self.sibling_accessor(file, func, FnKind::Getter); + let getter = self.sibling_accessor_at_this_moment(file, func, FnKind::Getter); ( 7032, getter.is_none_or(|(of, g)| self.accessor_has_no_type_source(of, g)), ) } else { // The error is reported on the setter, if possible. - let setter = self.sibling_accessor(file, func, FnKind::Setter); + let setter = self.sibling_accessor_at_this_moment(file, func, FnKind::Setter); ( 7033, setter.is_none_or(|(of, s)| { @@ -134,8 +134,30 @@ impl Checker<'_, '_> { } } - /// `(string) => void` was meant to be `(arg0: string) => void`. `IsTypeNodeKind` - pub(super) fn is_name_of_a_type(&self, file: FileId, func: FnId, name: Atom) -> bool { + /// `reportImplicitAny`, `case KindParameter`: the name of the parameter `p`, if it is an + /// identifier and `p.Parent` is a call signature, a method signature or a function type. + pub(super) fn identifier_of_signature_parameter( + &self, + file: FileId, + p: ParamId, + ) -> Option { + let (hir, bound) = (self.hir(file), self.bound(file)); + let func = bound.param_fn[p.idx()]; + let PatKind::Ident(name) = hir[hir[p].pat].kind else { + return None; + }; + let is_signature = func.is_some() + && match hir[func].kind { + FnKind::CallSignature | FnKind::FunctionType => true, + FnKind::Method => matches!(bound.fns[func.idx()].owner, FnOwner::Member(m) + if !matches!(bound.member_owner[m.idx()], MemberOwner::Class(_))), + _ => false, + }; + is_signature.then_some(name) + } + + /// `IsTypeNodeKind(IdentifierToKeywordKind(name))` + pub(super) fn is_type_node_keyword(&self, name: Atom) -> bool { const KEYWORDS: [&[u8]; 12] = [ b"any", b"unknown", @@ -150,7 +172,12 @@ impl Checker<'_, '_> { b"never", b"intrinsic", ]; - if KEYWORDS.contains(&self.atoms().bytes(name)) { + KEYWORDS.contains(&self.atoms().bytes(name)) + } + + /// `(string) => void` was meant to be `(arg0: string) => void`. `check_unused` notes the use. + pub(super) fn is_name_of_a_type(&self, file: FileId, func: FnId, name: Atom) -> bool { + if self.is_type_node_keyword(name) { return true; } let scope = self.bound(file).fns[func.idx()].scope; @@ -160,24 +187,4 @@ impl Checker<'_, '_> { .resolve_name(file, scope, name, SymFlags::TYPE) .is_some() } - - /// `checkVariableLikeDeclaration` returns before it requests the type of a renamed element in a - /// function without a body. 7031 comes from `getTypeFromBindingPattern`, which only runs once - /// the type of the parameter is requested: by another element of the pattern, by a call, or by - /// a comparison with another signature. - pub(super) fn is_parameter_type_never_requested( - &self, - file: FileId, - func: FnId, - p: ParamId, - ) -> bool { - let (hir, bound) = (self.hir(file), self.bound(file)); - let (f, symbol) = (&hir[func], bound.fn_symbol[func.idx()]); - f.kind == FnKind::Decl - && matches!(f.body, FnBody::None) - && matches!(hir[hir[p].pat].kind, PatKind::Object(props) if props.iter().all(|q| self.is_renamed_binding_element(file, q))) - && symbol.is_some() - && bound.symbols[symbol.idx()].decls.len() == 1 - && !bound.expr_symbol.contains(&symbol) - } } diff --git a/src/sema/check/errors_isolated_declarations.rs b/src/sema/check/errors_isolated_declarations.rs index e317052717e6..50c6e57362b5 100644 --- a/src/sema/check/errors_isolated_declarations.rs +++ b/src/sema/check/errors_isolated_declarations.rs @@ -56,8 +56,7 @@ pub(super) enum Pseudo { Literal(ExprId), } -/// `PseudoParameter`. A leading `this` is not one: its type is annotated, and is visited where the -/// others are emitted. +/// `PseudoParameter` pub(super) struct PseudoParam { pub(super) param: ParamId, pub(super) is_optional: bool, @@ -229,7 +228,7 @@ impl<'p, 's> Checker<'p, 's> { } /// `IsDefinitelyReferenceToGlobalSymbolObject` - fn iso_is_global_symbol_reference(&self, file: FileId, e: ExprId) -> bool { + fn iso_is_global_symbol_reference(&mut self, file: FileId, e: ExprId) -> bool { let hir = self.hir(file); if !is_entity_name_expression(self.hir(file), e) { return false; @@ -554,6 +553,9 @@ impl<'p, 's> Checker<'p, 's> { return Some(self.type_of_symbol(self.files().sym(file, symbol))); } NodeData::VarDecl(d) => of_pattern(hir[d].pat)?, + NodeData::Param(p) if self.is_this_parameter(file, p) => { + return Some(self.type_of_this_parameter(file, bound.param_fn[p.idx()])); + } NodeData::Param(p) => return Some(self.type_of_param(file, p)), NodeData::PatProp(p) => of_pattern(hir[p].value)?, NodeData::PatElem(p) => of_pattern(hir[p].pat)?, @@ -1184,7 +1186,14 @@ impl<'p, 's> Checker<'p, 's> { let hir = self.hir(file); let params = hir[func].params; let last_required = Self::iso_last_required(hir, params); - let mut all = Vec::with_capacity(params.len()); + let mut all = Vec::with_capacity(params.len() + 1); + if let Some(this) = hir[func].this_param.some() { + all.push(PseudoParam { + param: this, + is_optional: false, + ty: self.iso_pseudo_of_param(file, this), + }); + } for (i, p) in params.iter().enumerate() { let is_optional = hir[p].flags.contains(Flags::OPTIONAL) || hir[p].default.is_some() && i + 1 >= last_required; @@ -1209,20 +1218,26 @@ impl<'p, 's> Checker<'p, 's> { if hir[func].kind == FnKind::Setter { return self.iso_pseudo_of_accessor(file, func); } + // "Fast path: no initializer means we never need parameter position info." + if param.default.is_none() { + return match param.ty.some() { + Some(written) => Pseudo::Direct(written), + None => Pseudo::NoResult(hir.node(p)), + }; + } let is_strict = self.files().options.strict_null_checks; let params = hir[func].params; let has_required_after = (p.0 - params.start) as usize + 1 < Self::iso_last_required(hir, params); if param.ty.is_some() { let written = Pseudo::Direct(param.ty); - return if is_strict && param.default.is_some() && has_required_after { + return if is_strict && has_required_after { Self::iso_add_undefined(hir, written) } else { written }; } - if param.default.is_none() - || !matches!(hir[param.pat].kind, PatKind::Ident(_)) + if !matches!(hir[param.pat].kind, PatKind::Ident(_)) || self.iso_is_contextually_typed(file, hir.node(p)) { return Pseudo::NoResult(hir.node(p)); @@ -1348,6 +1363,12 @@ impl<'p, 's> Checker<'p, 's> { // ───────────────────────────── optional parameters ───────────────────────────── + /// Whether `p` is `GetThisParameter` of its function. + pub(super) fn is_this_parameter(&self, file: FileId, p: ParamId) -> bool { + let func = self.bound(file).param_fn[p.idx()]; + func.is_some() && self.hir(file)[func].this_param == p + } + /// `isOptionalParameter` pub(super) fn is_optional_parameter(&mut self, file: FileId, p: ParamId) -> bool { let (hir, bound) = (self.hir(file), self.bound(file)); @@ -1884,6 +1905,30 @@ impl<'p, 's> Checker<'p, 's> { reports: bool, elsewhere: Node, ) -> bool { + let mut params = params; + if let Some((this, _)) = self.sig_this_parameter(sig) { + let Some((first, rest)) = params + .split_first() + .filter(|(first, _)| self.is_this_parameter(tx.file, first.param)) + else { + if reports { + tx.inference_fallbacks.push(elsewhere); + } + return false; + }; + let options = EquivalenceOptions { + is_optional_annotated: first.is_optional, + reports: false, + }; + if !self.iso_is_equivalent(tx, &first.ty, this, options) { + if reports { + tx.inference_fallbacks + .push(self.hir(tx.file).node(first.param)); + } + return false; + } + params = rest; + } let targets = self.sig_params(sig); if targets.len() != params.len() { if reports { diff --git a/src/sema/check/errors_iteration.rs b/src/sema/check/errors_iteration.rs index 957f05119106..9c22d955b8ab 100644 --- a/src/sema/check/errors_iteration.rs +++ b/src/sema/check/errors_iteration.rs @@ -98,13 +98,15 @@ impl Checker<'_, '_> { pub(super) fn check_iteration(&mut self, file: FileId) { let (hir, bound) = (self.hir(file), self.bound(file)); let index = self.exprs_by_kind(file); - // `f(...x)`, `import(...x)`. `checkArrayLiteral` reports for `[...x]`. + // `f(...x)`, `import(...x)`. `checkArrayLiteral` reports for `[...x]`. Where a signature + // is applied, `check_argument` or `spread_argument_type` has made the request before. for &e in index.of(ExprTag::Spread) { let ExprKind::Spread(inner) = hir[e].kind else { continue; }; if matches!(bound.expr_parent[e.idx()], Parent::Expr(p) if matches!(hir[p].kind, ExprKind::Call(_) | ExprKind::New(_) | ExprKind::ImportCall { .. })) && !self.is_definite_assignment_target(file, e) + && !self.is_never_checked(hir[e].pos) { let actual = self.type_of_expr(file, inner); if !self.is_spread_of_array_like(file, e, actual) { @@ -248,6 +250,22 @@ impl Checker<'_, '_> { // `checkBinaryExpression`. Errors in `left` as a reference are reported with the // operators. let initializer = self.type_of_expr(file, value); + // `{ a = d }` is no `BinaryExpression`. + let (holder, is_shorthand) = match self.bound(file).expr_parent[node.idx()] { + Parent::Expr(array) => (array, false), + Parent::Prop(p) => ( + self.bound(file).prop_owner[p.idx()], + hir[p].kind == PropKind::Shorthand, + ), + _ => (ExprId::NONE, false), + }; + // `checkExpression` of the pattern, for the contextual type of the right side, has come + // to `node` before this, with `c.currentNode = node`. + let save_current_node = self.current_source_element; + if !is_shorthand && holder.is_some() && self.cached_type_of_expr(file, holder).is_some() + { + self.enter_source_element(CurrentNode::Expr(file, node)); + } if self.is_assignment_pattern(file, left) { self.check_destructuring_assignment(file, left, initializer); } else if why_no_reference(hir, left, 2364, 2779).is_none() { @@ -265,9 +283,9 @@ impl Checker<'_, '_> { None, ); } + self.current_source_element = save_current_node; // The default of `{ a = d }` removes `undefined` from the source type only if it cannot // be `undefined` itself. - let is_shorthand = matches!(self.bound(file).expr_parent[node.idx()], Parent::Prop(p) if hir[p].kind == PropKind::Shorthand); if self.p.files.options.strict_null_checks && !(is_shorthand && self.is_possibly_undefined(initializer)) { @@ -296,7 +314,7 @@ impl Checker<'_, '_> { } /// `hasDefaultValue` - fn has_default_value(&self, file: FileId, e: ExprId) -> bool { + pub(super) fn has_default_value(&self, file: FileId, e: ExprId) -> bool { let hir = self.hir(file); matches!(hir[e].kind, ExprKind::Assign { op: None, .. }) && !is_parenthesized(hir, e) } @@ -344,6 +362,7 @@ impl Checker<'_, '_> { self.error_at((file, start, self.end_of_prop(file, p)), 2462, &[]); return; } + self.note_external_emit_helpers_check(file, node); // A name that is not numeric omits the property of that name and no other. Any other // name omits by its type. let (mut names, mut keys) = (Vec::new(), Vec::new()); @@ -351,14 +370,20 @@ impl Checker<'_, '_> { .iter() .filter(|&other| hir[other].kind != PropKind::Spread) { - let (key, name_kind) = (hir[other].key, hir[other].name_kind); + let (key, name_kind, pos) = (hir[other].key, hir[other].name_kind, hir[other].pos); match key { PropKey::Name(name) if !self.is_numeric_name(name) => names.push(name), - _ => keys.extend(self.literal_type_from_property_name(file, key, name_kind)), + _ => { + keys.extend(self.literal_type_from_property_name(file, key, name_kind, pos)) + } } } let keys = self.union(&keys); - let rest = self.rest_of_object(object_literal_type, &names, keys, None); + // `objectLiteralType.symbol` + let assigned_symbol = self.symbol_of_type(object_literal_type); + let assigned_symbol = assigned_symbol.and_then(|it| it.of_binder()); + let rest = + self.rest_of_object(object_literal_type, &names, keys, None, assigned_symbol); // `checkGrammarForDisallowedTrailingComma` let end = self.end_of_prop(file, p); self.grammar_error_on_token_after(file, end, b',', 1013); @@ -373,8 +398,9 @@ impl Checker<'_, '_> { } return; } + let (key, name_kind) = (property.key, property.name_kind); let Some(expr_type) = - self.literal_type_from_property_name(file, property.key, property.name_kind) + self.literal_type_from_property_name(file, key, name_kind, property.pos) else { return; }; @@ -545,7 +571,15 @@ impl Checker<'_, '_> { let (message, optional_message) = if is_rest { (2701, 2778) } else { (2364, 2779) }; if self.check_reference_expression(file, target, message, optional_message) { let error_node = Some(self.error_range_of(file, target)); - self.check_type_assignable_to(source_type, target_type, error_node, None); + self.check_type_assignable_to_and_optionally_elaborate( + source_type, + target_type, + error_node, + Some((file, target)), + false, + None, + None, + ); } } @@ -558,13 +592,44 @@ impl Checker<'_, '_> { contextual: SigId, ) { let hir = self.hir(file); - let mut parameters = hir[func].params.iter(); - if parameters.any(|p| Self::is_pattern_without_names(hir, hir[p].pat)) { + // `needCheckInitializer || needCheckWidenedType` + let is_asked_for = hir[func].params.iter().any(|p| { + matches!(hir[hir[p].pat].kind, PatKind::Object(_) | PatKind::Array(_)) + && (hir[p].default.is_some() || Self::is_pattern_without_names(hir, hir[p].pat)) + }); + if is_asked_for { self.contextual_signatures_at_check .push(((file, func), contextual)); } } + /// `getContextuallyTypedParameterType` for parameter `index` of `func`, asked by + /// `checkVariableLikeDeclaration`: `contextuallyCheckFunctionExpressionOrObjectLiteralMethod` + /// checks the parameters while `getContextualSignature` still returns the signature that the + /// inference context then instantiates. The flag is false if another task has checked the + /// function: only the instantiated signature is stored, and the type is read from that one. + pub(super) fn contextual_param_type_at_check( + &mut self, + file: FileId, + func: FnId, + index: usize, + ) -> (Option, bool) { + let assigned = self.contextual_param_type(file, func, index); + if assigned.is_none() || self.iife_param_type(file, func, index).is_some() { + return (assigned, true); + } + let mut noted = self.contextual_signatures_at_check.iter(); + if let Some(sig) = noted.rfind(|it| it.0 == (file, func)).map(|it| it.1) { + return (self.contextual_param_type_in(file, func, index, sig), true); + } + let sig = self.assigned_contextual_signature(file, func); + let is_as_declared = sig.is_some_and(|sig| { + matches!(*self.types().sig(sig), SigData::Decl { mapper, .. } + if !self.is_instantiating(mapper)) + }); + (assigned, is_as_declared) + } + /// `checkVariableLikeDeclaration`, "For a binding pattern, validate the initializer and exit", /// where `needCheckWidenedType`: no element of `pat` has a name, so no element requests the /// destructured type. @@ -613,30 +678,11 @@ impl Checker<'_, '_> { .param_type_of_full_signature(file, func, index) .is_none() { - contextually_typed = self.contextual_param_type(file, func, index); - } - // `contextuallyCheckFunctionExpressionOrObjectLiteralMethod` checks the parameters - // while `getContextualSignature` still returns the signature that the inference - // context then instantiates. - if contextually_typed.is_some() && self.iife_param_type(file, func, index).is_none() { - let mut noted = self.contextual_signatures_at_check.iter(); - match noted.rfind(|it| it.0 == (file, func)).map(|it| it.1) { - Some(sig) => { - contextually_typed = self.contextual_param_type_in(file, func, index, sig); - } - // Another task has checked the function. Only the instantiated signature is - // stored. - None => { - let assigned = self.assigned_contextual_signature(file, func); - let is_as_declared = assigned.is_some_and(|sig| { - matches!(*self.types().sig(sig), SigData::Decl { mapper, .. } - if !self.is_instantiating(mapper)) - }); - if !is_as_declared { - return; - } - } + let (ty, is_known) = self.contextual_param_type_at_check(file, func, index); + if !is_known { + return; } + contextually_typed = ty; } if hir[q].flags.contains(Flags::OPTIONAL) { contextually_typed = contextually_typed.map(|ty| self.optional(ty)); diff --git a/src/sema/check/errors_js.rs b/src/sema/check/errors_js.rs index 75de722844ca..e3a19f90b6bc 100644 --- a/src/sema/check/errors_js.rs +++ b/src/sema/check/errors_js.rs @@ -100,10 +100,13 @@ impl Checker<'_, '_> { let mut previous_owner = None; for &(owner, decorator) in &hir.decorators { if previous_owner.replace(owner) != Some(owner) - && let DecoratorOwner::Param(p) = owner + && matches!(owner, DecoratorOwner::Param(_)) { - // `decorator.Loc`, which starts at the end of the previous token. - let at = (file, hir[p].loc.pos, end_of_expr(hir, decorator)); + // `decorator.Loc`, which starts at the end of the previous token: `export` and + // `default` can come before it. + let at_sign = self.decorator_position(file, decorator).at_sign; + let pos = self.end_of_token_before(file, at_sign); + let at = (file, pos, end_of_expr(hir, decorator)); self.add_diagnostic(Reported::bare(at, 1206)); } } diff --git a/src/sema/check/errors_jsx.rs b/src/sema/check/errors_jsx.rs index 576e7a2e5942..7e83c7297b66 100644 --- a/src/sema/check/errors_jsx.rs +++ b/src/sema/check/errors_jsx.rs @@ -34,21 +34,12 @@ impl Checker<'_, '_> { let path = self.files().module(file).file_name(); // The only atom it reads is one that the parser interned. let runtime = crate::program::jsx_runtime_of(options, hir, &self.p.files.atoms) - .filter(|_| path.ends_with(b".tsx") || path.ends_with(b".jsx")) + .filter(|_| crate::resolve::is_jsx_file_name(path)) .map(|spec| atoms.intern(&spec)); // `getJsxNamespaceContainerForImplicitImport`: the JSX runtime module is imported // implicitly, and must exist. let runtime_is_missing = runtime.is_some_and(|spec| self.files().module_of_specifier(file, spec).is_none()); - // `resolveExternalModule`: for a file that resolves but is not a module, that error is - // reported. - let runtime_is_no_module = - runtime.is_some_and(|spec| self.files().module(file).imported_file(spec).is_some()); - // For JavaScript that is not in the program, the error of `errorOnImplicitAnyModule`. - let module = self.files().module(file); - let untyped_runtime = runtime - .map(|spec| (spec, module.default_mode)) - .filter(|untyped| !runtime_is_no_module && module.untyped_imports.contains(untyped)); let (factory, fragment_factory) = ( jsx_namespace(self.files(), self.atoms(), hir, false), jsx_namespace(self.files(), self.atoms(), hir, true), @@ -89,7 +80,7 @@ impl Checker<'_, '_> { // An error reported once per file is reported on the element that is checked first. // Elements the walk does not reach come last, in source order. let (mut first, mut first_fragment) = (None, None); - if runtime_is_missing || checks_fragment_type { + if runtime.is_some() || checks_fragment_type { // Only this task stores the entry of a JSX element of the file (`is_noted_for_check_file`), so it has evaluated each itself. let reached = match self.first_jsx { (of, first, first_fragment) if of == file => (first, first_fragment), @@ -118,26 +109,25 @@ impl Checker<'_, '_> { } self.resolved_signature(file, e); self.report_call_resolution(file, e); - if runtime_is_missing && first == Some(e) { + if first == Some(e) + && let Some(spec) = runtime + { // `checkJsxElement` passes the whole element to `getJsxElementTypeAt`. In a file that is emitted before it is checked, // `MarkLinkedReferencesRecursively` comes first, where `markJsxAliasReferenced` passes the opening element. let is_whole_element = self.p.files.options.no_emit && element.tag.is_some() && element.close_pos != u32::MAX; let end = if is_whole_element { element.end } else { end }; - if let Some((spec, mode)) = untyped_runtime { - if no_implicit_any { - self.error_on_implicit_any_module(file, spec, mode, (file, start, end)); - } - } else if let Some(spec) = runtime { - match self.files().module(file).imported_file(spec) { - Some(found) => { - let path = self.files().module(found).file_name(); - self.error_at((file, start, end), 2306, &[Arg::Path(path)]) - } - None => self.error_at((file, start, end), 2875, &[Arg::Atom(spec)]), - }; - } + // `getJSXRuntimeImportSpecifier`: the specifier of the synthetic import the loader + // added, which has no import clause and is nowhere in the text. + let specifier = SpecifierUse { + spec, + pos: u32::MAX, + kind: SpecifierKind::Import, + mode: self.files().module(file).default_mode, + }; + let (site, location) = (SpecifierSite::default(), (file, start, end)); + self.resolve_external_module_at(file, specifier, site, location, Some(2875)); } // `resolveName`, starting at `jsxFactoryLocation`: the tag name, or the opening fragment. let scope = bound.expr_scope.get(&e).copied().unwrap_or(ScopeId(0)); @@ -327,7 +317,7 @@ impl Checker<'_, '_> { return false; } self.resolved_signature(file, e); - let list = hir[first].pos..self.end_of_type_argument_list(file, type_args); + let list = start_of_type(hir, first)..self.end_of_type_argument_list(file, type_args); (self.p.call_diagnostics) .get_ref(&self.task, &(file, e)) .is_some_and(|reported| reported.iter().any(|d| list.contains(&d.start))) @@ -455,7 +445,7 @@ impl Checker<'_, '_> { if let Some(first) = hir.ids(jsx.type_args).next() { let end = self.end_of_type_argument_list(file, jsx.type_args); let args = [Arg::Number(0), Arg::Number(jsx.type_args.len())]; - self.error_at((file, hir[first].pos, end), 2558, &args); + self.error_at((file, start_of_type(hir, first), end), 2558, &args); } return resolved; } else { @@ -882,8 +872,9 @@ impl Checker<'_, '_> { return reported; }; let more_than_one_real_children = valid_children.next().is_some(); - // Where there is no `Iterable`, a list is an array-like or tuple-like type. - let has_iterable = self.global_type_symbol(known::Iterable).is_some(); + // `getGlobalIterableType() != emptyGenericType`. Where there is no such `Iterable`, a list is + // an array-like or tuple-like type. + let has_iterable = self.global_type_of_arity(known::Iterable, 3).is_some(); let any_iterable = self.global_ref( known::Iterable, &[TypeId::ANY, TypeId::VOID, TypeId::UNDEFINED], diff --git a/src/sema/check/errors_modules.rs b/src/sema/check/errors_modules.rs index bf7ff1bee430..61b6c764a5ab 100644 --- a/src/sema/check/errors_modules.rs +++ b/src/sema/check/errors_modules.rs @@ -4,8 +4,8 @@ //! * `bindModuleDeclaration`: 2668 5061; `bindNamespaceExportDeclaration`: 1184 1314 1315 1316 //! * `checkModuleDeclaration`: 1035 1280 1287 1540 2435 2436 2669 2670; //! `checkModuleAugmentationElement`: 2666 2667 -//! * `mergeModuleAugmentation`, and the errors `resolveExternalModule` and `mergeSymbol` report on -//! its behalf: 2306 2567 2649 2664 2665 2671 2732 2834 2835 +//! * `mergeModuleAugmentation`, and the errors `resolveExternalModule` reports on its behalf: 2306 +//! 2664 2665 2671 2732 2834 2835 //! * `checkExternalImportOrExportDeclaration`: 1147 1194 2439 2858 //! * `collectModuleReferences`, via `resolveExternalModule`: 2307 2580 2591 2732 2882, reported or //! removed @@ -28,10 +28,9 @@ //! starting at a position the HIR does have. A declaration file has no text, so checks that depend //! on the text are skipped. -use super::errors_enums_names::resolves_to_umd_global; use super::*; use crate::bind::{Decl, Parent, ScopeId, SymbolId}; -use crate::resolve::{ModuleKind, is_relative}; +use crate::resolve::{ModuleKind, is_relative, normalize_path}; use bun_collections::ArrayHashMap; /// State that is constant for a whole file. @@ -81,16 +80,6 @@ impl Cx<'_> { let at = self.uses.partition_point(|u| u.pos < pos); self.uses.get(at).copied().filter(|u| u.spec == spec) } - - /// `importClause.NamedBindings` is a `NamedImports`. The HIR has no node for `{}` after a - /// default import: the clause ends with the brace. - fn has_named_imports(&self, import: &Import) -> bool { - import.namespace.is_none() - && (!import.named.is_empty() - || import.clause_end > import.clause_start - && (import.default.is_none() - || self.text.get(import.clause_end as usize - 1) == Some(&b'}'))) - } } impl Checker<'_, '_> { @@ -142,28 +131,19 @@ impl Checker<'_, '_> { self.modules_statements(&cx, hir.body, top); self.modules_misplaced_statements(&cx, top); self.modules_import_calls_and_types(&cx); - // Fast path: a cycle needs an alias that other files can import, or one that refers to another name in this file. - let can_be_circular = cx.aliases.keys().iter().any(|d| { - matches!( - d, - Decl::ImportEquals(_) - | Decl::ExportSpec(_) - | Decl::ExportStarAs(_) - | Decl::ExportExpr(_) - | Decl::ModuleExports(_) - | Decl::ExportsProperty(_) - ) - }); for (&decl, &sym) in cx.aliases.iter() { // `checkVariableLikeDeclaration` - if matches!(decl, Decl::Require(_)) { - self.check_alias_symbol(file, &cx.aliases, decl, false); + if let Decl::Require(name) = decl { + if self.is_never_checked(hir[name].pos) { + self.modules_resolve_alias_if_used(&cx, decl); + } else { + self.check_alias_symbol(file, &cx.aliases, decl, false); + } } // `resolveAlias`: at `getDeclarationOfAliasSymbol`. Where // `checkGrammarModuleElementContext` stops the check of the declaration, something else // has to resolve the alias. - if can_be_circular - && self.files().alias_links(sym).is_circular + if self.files().alias_links(sym).is_circular && self.files().declaration_of_alias_symbol(sym) == Some((file, decl)) && (statement_of_alias_declaration(hir, decl) .is_none_or(|s| is_in_appropriate_context(self.bound(file), s)) @@ -180,11 +160,13 @@ impl Checker<'_, '_> { } /// `reportFlowControlError`: reports 2563 at the first token of the function body, namespace body or file that contains a reference - /// whose control flow walk reached the depth limit. `flow_type_of` records those references in `flows_too_deep`. + /// whose control flow walk reached the depth limit. `report_flow_control_error` records those references in `flows_too_deep`, and + /// the blocks of those that are no expressions in `blocks_too_large_for_flow_analysis`. fn check_flow_too_deep(&mut self, file: FileId) { let (hir, bound) = (self.hir(file), self.bound(file)); - // The limit is 2000 levels, and a walk nests at most once per flow node. - if bound.flow_places <= 2000 { + // The limit is 2000 levels. A walk nests at most once per flow node, and once for the + // condition that `checkIfExpressionRefinesParameter` synthesizes. + if bound.flow_places < 2000 { return; } let mut reported = Node::NONE; @@ -200,28 +182,42 @@ impl Checker<'_, '_> { } let block = self.function_or_module_block_of(file, e); // Consecutive references usually share a block. - if block == reported { - continue; - } - // `GetRangeOfTokenAtPosition(sourceFile, block.StatementList().Pos())` - let start = if block == Node::FILE { - Some(first_token_start(&hir.text)) - } else if let NodeData::Stmt(s) = hir.data(block.row()) - && let StmtKind::Module(m) = hir[s].kind - { - statement_list_start(hir, hir[m].body) - } else if let Some(FnBody::Block(statements)) = - (hir.fns.get(hir.function_of(block.row()).idx())).map(|f| f.body) - { - statement_list_start(hir, statements) - } else { - None - }; - if let Some(start) = start { + if block != reported && self.report_block_too_large_for_flow_analysis(file, block) { reported = block; - self.error_at((file, start, 0), 2563, &[]); } } + let functions = (0..hir.fns.len() as u32).map(|f| hir.node(FnId(f))); + let namespaces = (0..hir.modules.len() as u32).map(|m| hir.node(ModuleId(m))); + let owners = functions.chain(namespaces).filter(|owner| owner.is_some()); + for block in std::iter::once(Node::FILE).chain(owners.map(|owner| hir.body(owner))) { + let blocks = &self.p.blocks_too_large_for_flow_analysis; + if blocks.get(&self.task, &(file, block)).is_some() { + self.report_block_too_large_for_flow_analysis(file, block); + } + } + } + + /// 2563 at `GetRangeOfTokenAtPosition(sourceFile, block.StatementList().Pos())`. `false`: the + /// block has no statement. + fn report_block_too_large_for_flow_analysis(&mut self, file: FileId, block: Node) -> bool { + let hir = self.hir(file); + let start = if block == Node::FILE { + Some(first_token_start(&hir.text)) + } else if let NodeData::Stmt(s) = hir.data(block.row()) + && let StmtKind::Module(m) = hir[s].kind + { + statement_list_start(hir, hir[m].body) + } else if let Some(FnBody::Block(statements)) = + (hir.fns.get(hir.function_of(block.row()).idx())).map(|f| f.body) + { + statement_list_start(hir, statements) + } else { + None + }; + if let Some(start) = start { + self.error_at((file, start, 0), 2563, &[]); + } + start.is_some() } /// `GetEmitModuleFormatOfFile(file) == ModuleKindCommonJS` @@ -440,72 +436,40 @@ impl Checker<'_, '_> { } /// What `mergeModuleAugmentation` reports for the declaration `m`, which augments the module - /// named `name`. `Files::merge` has merged it. Errors are reported at the first declaration of - /// its symbol. + /// named `name`. `Files::merge` has merged it, and `check_refused_merges` reports what + /// `mergeSymbol` does. fn modules_merge_augmentation(&mut self, cx: &Cx<'_>, m: ModuleId, name: Atom, around: Around) { let (hir, bound, files) = (self.hir(cx.file), self.bound(cx.file), self.files()); let symbol = bound.module_symbol[m.idx()]; - if symbol.is_none() || !files.merges_module_augmentation(cx.file, symbol) { + // "do the work only for first declaration" + if symbol.is_none() + || !files.merges_module_augmentation(cx.file, symbol) + || bound.symbols[symbol.idx()].decls.first() != Some(&Decl::Module(m)) + { return; } - let decls = &bound.symbols[symbol.idx()].decls; - let is_first = decls.first() == Some(&Decl::Module(m)); let start = hir[m].name_pos; - let report = |c: &mut Self, code: u32, of_each: bool, args: &[Arg<'_>]| { - if of_each || is_first { - c.error_at((cx.file, start, 0), code, args); - } - }; // `resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError, false, // true)`. Names in an ambient context are not reported. - if is_first { - let written = SpecifierUse { - spec: name, - pos: start, - kind: SpecifierKind::Import, - mode: ResolutionMode::None, - }; - let site = SpecifierSite { - is_ambient: true, - is_for_augmentation: true, - is_not_validated: around.is_ambient, - ..Default::default() - }; - self.resolve_external_module(cx.file, written, site); - } + let written = SpecifierUse { + spec: name, + pos: start, + kind: SpecifierKind::Import, + mode: ResolutionMode::None, + }; + let site = SpecifierSite { + is_ambient: true, + is_for_augmentation: true, + is_not_validated: around.is_ambient, + ..Default::default() + }; + self.resolve_external_module(cx.file, written, site); let own = Sym { file: cx.file, id: symbol, }; if files.augmentations_of_non_modules.contains(&own) { - report(self, 2671, false, &[Arg::Atom(name)]); - return; - } - let merged = files.canonical(own); - if files.flags(merged).contains(SymFlags::TRANSIENT) { - return; - } - let Some(found) = files.module_of_specifier(cx.file, name) else { - return; - }; - let main = files.module_value(found); - let flags = files.flags(main); - // `mergeSymbol`, `SymbolFlagsValueModuleExcludes`: a module that contains values merges - // with neither a variable nor a `const enum`, whatever else has the same name. - let is_variable = flags.intersects(SymFlags::VARIABLE); - let is_const_enum = || { - files.decls(main).iter().any(|&(of, d)| matches!(d, Decl::Enum(e) if files.hir(of)[e].flags.contains(Flags::CONST))) - }; - let has_values = || { - decls.iter().any(|&d| matches!(d, Decl::Module(part) if bound.module_instance_state[part.idx()] != ModuleInstanceState::NonInstantiated)) - }; - if (is_variable || flags.intersects(SymFlags::ENUM) && is_const_enum()) && has_values() { - if flags.contains(SymFlags::NAMESPACE_MODULE) { - report(self, 2649, false, &[Arg::Sym(main)]); - } else if !is_variable { - // `reportMergeSymbolError` for the declarations on this side. - report(self, 2567, true, &[]); - } + self.error_at((cx.file, start, 0), 2671, &[Arg::Atom(name)]); } } @@ -633,19 +597,73 @@ impl Checker<'_, '_> { self.resolve_external_module(file, written, site) } - /// What `resolveAlias(sym)` reports through `getTargetOfAliasDeclaration`, for a caller other - /// than the check of the declaration: `resolveExternalModuleName`, then - /// `check_target_of_alias_declaration`. + /// What `resolveAlias(sym)` reports, for a caller other than the check of the declaration: + /// `getTargetOfAliasDeclaration`, which is `check_target_of_export_specifier`, or + /// `resolveExternalModuleName` and then `check_target_of_alias_declaration`. pub(super) fn check_target_of_alias_symbol(&mut self, sym: Sym) { - let Some((file, decl)) = self.files().declaration_of_alias_symbol(sym) else { + let files = self.files(); + let Some((file, decl)) = files.declaration_of_alias_symbol(sym) else { return; }; // The HIR of a leaf is freed after its task. - if self.task.file != Some(file) && self.files().module(file).is_leaf { + if self.task.file != Some(file) && files.module(file).is_leaf { return; } let (hir, bound) = (self.hir(file), self.bound(file)); - let Some(s) = statement_of_alias_declaration(hir, decl) else { + let statement = statement_of_alias_declaration(hir, decl); + // FOR SPEED: nothing stops the check of such a declaration, which reports the same. + let has_phase_modifier = statement.is_some_and(|s| { + matches!(hir[s].kind, StmtKind::Import(x) if hir[x].type_only || hir[x].is_deferred) + }); + let is_checked = match statement { + Some(s) => { + matches!(bound.stmt_parent[s.idx()], Parent::File) + && hir.import_attributes.is_empty() + && !has_phase_modifier + } + // `checkWithStatement` does not check the body. + None => !matches!(decl, Decl::Require(name) if hir.is_in_with(hir[name].pos)), + }; + // `links.aliasTarget != nil`, `pushTypeResolution` + if is_checked || self.is_stack_low() || !self.alias_targets_reported.insert(sym) { + return; + } + self.alias_targets_in_progress.push(sym); + let from = self.reported.len(); + self.get_target_of_alias_declaration(file, sym, decl, statement); + // `resolveIndirectionAlias` + if let Some(target) = files.alias_links(sym).immediate_target + && files.is_non_local_alias(target) + { + self.check_target_of_alias_symbol(target); + } + self.alias_targets_in_progress.pop(); + for diagnostic in self.reported.iter_mut().skip(from) { + diagnostic.by_another_node = true; + } + // `aliasTarget` is assigned once, whatever becomes of the queries in progress. + if !self.frames.is_empty() { + self.log_reported_from(from); + } + } + + /// What `getTargetOfAliasDeclaration` reports for `decl`, the declaration in `file` of the + /// alias `sym`. `statement`: `statement_of_alias_declaration`. + fn get_target_of_alias_declaration( + &mut self, + file: FileId, + sym: Sym, + decl: Decl, + statement: Option, + ) { + let hir = self.hir(file); + let Some(s) = statement else { + // `getTargetOfImportEqualsDeclaration`, `getTargetOfImportSpecifier` + if let Decl::Require(name) = decl + && self.resolve_module_required_by(file, name) + { + self.check_target_of_alias_declaration(file, sym, decl); + } return; }; let spec = match hir[s].kind { @@ -655,25 +673,77 @@ impl Checker<'_, '_> { StmtKind::ExportStar { spec, .. } => spec, _ => Atom::NONE, }; - // FOR SPEED: nothing stops the check of such a declaration, which reports the same. - let has_phase_modifier = - matches!(hir[s].kind, StmtKind::Import(x) if hir[x].type_only || hir[x].is_deferred); - let is_checked = matches!(bound.stmt_parent[s.idx()], Parent::File) - && hir.import_attributes.is_empty() - && !has_phase_modifier; - if spec.is_none() || is_checked { - return; - } let start = hir[s].start; let is_written = |u: &&SpecifierUse| u.spec == spec && u.pos >= start && !u.kind.is_call(); let uses = hir.specifier_uses.iter().filter(is_written); - if let Some(&written) = uses.min_by_key(|u| u.pos) + if let Decl::ExportSpec(specifier) = decl + && !hir[hir[specifier].export].has_module_specifier + { + self.check_target_of_export_specifier(file, specifier); + } else if let Decl::ImportEquals(i) = decl + && let ImportEqualsTarget::Entity(names) = hir[i].target + { + // `getTargetOfImportEqualsDeclaration` + self.get_symbol_of_part_of_right_hand_side_of_import_equals(file, i, names); + self.aliases_import_alias_of_type_only(file, i, names); + } else if spec.is_some() + && let Some(&written) = uses.min_by_key(|u| u.pos) && self.resolve_external_module_name(file, s, written, hir.is_ambient(hir.node(s))) { self.check_target_of_alias_declaration(file, sym, decl); } } + /// What `getTypeOfAlias(sym)` reports for an alias whose target is `unknownSymbol`: + /// `resolveAlias`, then `getTargetOfAliasDeclaration` once more for `exportSymbol`. Only + /// `getTargetOfExportSpecifier` has something else to say then: `sym` is no longer in progress, + /// so `getSpellingSuggestionForName` can suggest it. + pub(super) fn check_export_symbol_of_alias(&mut self, sym: Sym) { + self.check_target_of_alias_symbol(sym); + if self.alias_targets_reported.contains(&sym) + && let Some((file, Decl::ExportSpec(specifier))) = + self.files().declaration_of_alias_symbol(sym) + && !self.hir(file)[self.hir(file)[specifier].export].has_module_specifier + { + self.check_target_of_export_specifier(file, specifier); + } + } + + /// What `getTargetOfExportSpecifier` reports for the specifier `s` of an `export { .. }` of + /// `file` that has no module specifier: `resolveEntityName`. Returns the name, its scope and + /// what it resolves to. `None`: it is a string literal. + fn check_target_of_export_specifier( + &mut self, + file: FileId, + s: ExportSpecId, + ) -> Option<(Node, ScopeId, Option)> { + let (hir, files) = (self.hir(file), self.files()); + let ExportSpec { + local: name, + local_pos: start, + export, + .. + } = hir[s]; + let scope = self.bound(file).export_scope[export.idx()]; + if scope.is_none() || matches!(hir.text.get(start as usize), Some(b'"' | b'\'')) { + return None; + } + // `PropertyNameOrName` + let location = match hir.property_name(hir.node(s)) { + Node::NONE => hir.name(hir.node(s)), + written => written, + }; + let all = SymFlags::VALUE | SymFlags::TYPE | SymFlags::NAMESPACE; + let resolved = files.resolve_name(file, scope, name, all); + if let Some(result) = resolved { + self.on_successfully_resolved_symbol(file, location, scope, result, all); + } else { + let message = self.get_cannot_find_name_diagnostic_for_name(file, location, name); + self.on_failed_to_resolve_symbol(file, location, None, scope, name, all, message); + } + Some((location, scope, resolved)) + } + /// `check_target_of_alias_symbol` for the alias that `decl` declares, in a statement whose /// check does not get to it, if something else resolves the alias. fn modules_resolve_alias_if_used(&mut self, cx: &Cx<'_>, decl: Decl) { @@ -732,7 +802,8 @@ impl Checker<'_, '_> { } /// Whether something other than the check of its declaration resolves the alias `sym`, which - /// the file declares: a reference in the file, or `getNamedMembers` of `typeof globalThis`. + /// the file declares: a reference in the file that is checked, or `getNamedMembers` of `typeof + /// globalThis`. fn modules_alias_is_used(&self, cx: &Cx<'_>, sym: Sym) -> bool { let (hir, bound, files) = (self.hir(cx.file), self.bound(cx.file), self.files()); let alias = files.symbol(sym).name; @@ -744,9 +815,9 @@ impl Checker<'_, '_> { }; // `checkGrammarModuleElementContext` stops the check of any other. let is_checked = |s: StmtId| is_in_appropriate_context(bound, s); - bound.expr_symbol.iter().zip(&bound.expr_parent).any(|(&s, parent)| s.is_some() && files.sym(cx.file, s) == sym && !matches!(parent, Parent::None)) + bound.expr_symbol.iter().zip(&bound.expr_parent).zip(hir.exprs.iter()).any(|((&s, parent), e)| s.is_some() && files.sym(cx.file, s) == sym && !matches!(parent, Parent::None) && !self.is_never_checked(e.pos)) || hir.types.iter().enumerate().any(|(t, node)| match node.kind { - TypeNodeKind::Ref { name, .. } | TypeNodeKind::Typeof { name, .. } => !name.is_empty() && means_it(bound.type_scope[t], hir[name.at(0)].text), + TypeNodeKind::Ref { name, .. } | TypeNodeKind::Typeof { name, .. } => !name.is_empty() && !self.is_never_checked(node.pos) && means_it(bound.type_scope[t], hir[name.at(0)].text), _ => false, }) || hir.import_equals.iter().enumerate().any(|(other, import)| { @@ -913,42 +984,50 @@ impl Checker<'_, '_> { /// `checkGrammarImportClause` fn check_grammar_import_clause(&mut self, cx: &Cx<'_>, i: ImportId) -> bool { - let hir = self.hir(cx.file); + let Some((at, code)) = self.grammar_error_of_import_clause(cx.file, i) else { + return false; + }; + if cx.grammar { + self.error_at(at, code, &[]); + } + cx.grammar + } + + /// What `checkGrammarImportClause` passes to `grammarErrorOnNode`, and where. + pub(super) fn grammar_error_of_import_clause( + &self, + file: FileId, + i: ImportId, + ) -> Option<((FileId, u32, u32), u32)> { + let hir = self.hir(file); let import = hir[i]; - let has_named_imports = cx.has_named_imports(&import); - let clause = (cx.file, import.clause_start, import.clause_end); - let (at, code) = if import.type_only { - let has_named_bindings = import.namespace.is_some() || has_named_imports; - let mut specifiers = import.named.iter(); - if import.default.is_some() - && has_named_bindings - && !hir.is_in_jsdoc(import.clause_start) + let clause = (file, import.clause_start, import.clause_end); + let code = if import.type_only { + let has_named_bindings = import.namespace.is_some() || import.has_named_imports; + if import.default.is_none() + || !has_named_bindings + || hir.is_in_jsdoc(import.clause_start) { - (clause, 1363) - // `checkGrammarTypeOnlyNamedImportsOrExports` - } else if let Some(specifier) = specifiers.find(|&it| hir[it].type_only) { - ((cx.file, hir[specifier].start, 0), 2206) - } else { - return false; + // `checkGrammarTypeOnlyNamedImportsOrExports` + let specifier = import.named.iter().find(|&it| hir[it].type_only)?; + return Some(((file, hir[specifier].start, 0), 2206)); } + 1363 } else if !import.is_deferred { - return false; + return None; } else if import.default.is_some() { - (clause, 18058) - } else if has_named_imports { - (clause, 18059) + 18058 + } else if import.has_named_imports { + 18059 } else if !matches!( self.p.files.options.module, ModuleKind::EsNext | ModuleKind::Preserve ) { - (clause, 18060) + 18060 } else { - return false; + return None; }; - if cx.grammar { - self.error_at(at, code, &[]); - } - cx.grammar + Some((clause, code)) } /// `checkImportBinding` for the declaration `decl` of `name`, but for `checkModuleExportName`. @@ -967,12 +1046,16 @@ impl Checker<'_, '_> { mode: ResolutionMode, ) -> Option { let (files, importing) = (self.files(), self.files().module(file)); + if let Some(ambient_module) = files.try_find_ambient_module(spec) { + return Some(ambient_module); + } let mut arbitrary = importing.arbitrary_extension_imports.iter(); let source_file = arbitrary .position(|&u| u == (spec, mode)) .and_then(|index| { let resolved_file_name = importing.arbitrary_extension_files[index]; - files.by_path.get(self.atoms().bytes(resolved_file_name)) + let resolved_file_name = self.atoms().bytes(resolved_file_name).to_vec(); + files.by_path.get(&normalize_path(resolved_file_name)) }); match source_file { Some(source_file) if files.module(source_file).is_module() => { @@ -989,6 +1072,11 @@ impl Checker<'_, '_> { let context_error = if cx.is_js { 1473 } else { 1232 }; if self.check_grammar_module_element_context(cx, s, around, context_error) { self.modules_resolve_alias_if_used(cx, decl); + if let Some(&symbol) = cx.aliases.get(&decl) + && files.resolve_alias(symbol).is_none() + { + self.modules_mark_alias_symbol_as_referenced(cx, i); + } return; } let is_ambient = around.is_ambient || import.flags.contains(Flags::AMBIENT); @@ -1018,40 +1106,13 @@ impl Checker<'_, '_> { if import.flags.contains(Flags::TYPE_ONLY) { self.grammar_error_on_node(cx.file, s, 1392, &[]); } - let scope = bound.import_equals_scope[i.idx()]; - if scope.is_none() || names.is_empty() { - return; - } - let first = hir[names.at(0)]; - // `getSymbolOfPartOfRightHandSideOfImportEquals`: an unqualified name is resolved as a - // namespace. - let meaning = if names.len() == 1 { - SymFlags::NAMESPACE - } else { - SymFlags::VALUE | SymFlags::TYPE | SymFlags::NAMESPACE - }; - let Some(target) = self.resolve_entity_name(cx.file, scope, names, meaning, false) else { - // `canCollectSymbolAliasAccessibilityData` - if first.text == known::empty || files.options.verbatim_module_syntax { - return; - } - // `markAliasSymbolAsReferenced`: the first name of an alias that is not elided is also - // resolved as a value. - let value = SymFlags::VALUE | SymFlags::EXPORT_VALUE; - if self.modules_is_marked_as_referenced(cx, i, &mut Vec::new()) - && files - .resolve_name(cx.file, scope, first.text, value) - .is_none() - { - let location = hir.node(names.at(0)); - let message = - self.get_cannot_find_name_diagnostic_for_name(cx.file, location, first.text); - self.on_failed_to_resolve_symbol( - cx.file, location, None, scope, first.text, value, message, - ); - } + let Some(target) = + self.get_symbol_of_part_of_right_hand_side_of_import_equals(cx.file, i, names) + else { + self.modules_mark_alias_symbol_as_referenced(cx, i); return; }; + let (scope, first) = (bound.import_equals_scope[i.idx()], hir[names.at(0)]); let flags = files.symbol_flags(target); if flags == SymFlags::all() { return; @@ -1077,15 +1138,68 @@ impl Checker<'_, '_> { } } + /// `getSymbolOfPartOfRightHandSideOfImportEquals` for `names`, the right side of the + /// `import i = A.B` of `file`: an unqualified name is resolved as a namespace. + fn get_symbol_of_part_of_right_hand_side_of_import_equals( + &mut self, + file: FileId, + i: ImportEqualsId, + names: Span, + ) -> Option { + let scope = self.bound(file).import_equals_scope[i.idx()]; + if scope.is_none() || names.is_empty() { + return None; + } + let meaning = if names.len() == 1 { + SymFlags::NAMESPACE + } else { + SymFlags::VALUE | SymFlags::TYPE | SymFlags::NAMESPACE + }; + self.resolve_entity_name(file, scope, names, meaning, false) + } + + /// `markAliasSymbolAsReferenced` for the `import i = A.B`, whose target is `unknownSymbol`. + /// `getSymbolFlags(unknownSymbol)` has `Value`, so the first name of an alias that is not + /// elided is also resolved as a value. + fn modules_mark_alias_symbol_as_referenced(&mut self, cx: &Cx<'_>, i: ImportEqualsId) { + let (hir, files) = (self.hir(cx.file), self.files()); + let scope = self.bound(cx.file).import_equals_scope[i.idx()]; + let ImportEqualsTarget::Entity(names) = hir[i].target else { + return; + }; + if scope.is_none() || names.is_empty() { + return; + } + let name = hir[names.at(0)].text; + // `canCollectSymbolAliasAccessibilityData` + if name == known::empty + || files.options.verbatim_module_syntax + || !self.modules_is_marked_as_referenced(cx.file, &cx.aliases, i, &mut Vec::new()) + { + return; + } + // `markIdentifierAliasReferenced`: `getResolvedSymbol` + let value = SymFlags::VALUE | SymFlags::EXPORT_VALUE; + let location = hir.node(names.at(0)); + if let Some(result) = files.resolve_name(cx.file, scope, name, value) { + self.on_successfully_resolved_symbol(cx.file, location, scope, result, value); + } else { + let message = self.get_cannot_find_name_diagnostic_for_name(cx.file, location, name); + self.on_failed_to_resolve_symbol(cx.file, location, None, scope, name, value, message); + } + } + /// `aliasSymbolLinks.referenced` of the `import i = A.B`, whose target is `unknownSymbol`: /// whether `markAliasSymbolAsReferenced` is called for it. `seen`: those already asked about. - fn modules_is_marked_as_referenced( + /// `aliases`: `symbols_of_alias_declarations(file)`. + pub(super) fn modules_is_marked_as_referenced( &self, - cx: &Cx<'_>, + file: FileId, + aliases: &ArrayHashMap, i: ImportEqualsId, seen: &mut Vec, ) -> bool { - let (hir, bound, files) = (self.hir(cx.file), self.bound(cx.file), self.files()); + let (hir, bound, files) = (self.hir(file), self.bound(file), self.files()); let (import, scope) = (hir[i], bound.import_equals_scope[i.idx()]); seen.push(i); // `markLinkedReferences`: not where nothing is emitted. @@ -1117,7 +1231,7 @@ impl Checker<'_, '_> { } // `markAliasSymbolAsReferenced` of another `import =`: `markIdentifierAliasReferenced` for // the first name of its right side. - let Some(&symbol) = cx.aliases.get(&Decl::ImportEquals(i)) else { + let Some(&symbol) = aliases.get(&Decl::ImportEquals(i)) else { return false; }; let value = SymFlags::VALUE | SymFlags::EXPORT_VALUE; @@ -1128,8 +1242,8 @@ impl Checker<'_, '_> { if !names.is_empty() && hir[names.at(0)].text == import.name) && !seen.contains(&other) && from.is_some() - && files.resolve_name(cx.file, from, import.name, value) == Some(symbol) - && self.modules_is_marked_as_referenced(cx, other, seen) + && files.resolve_name(file, from, import.name, value) == Some(symbol) + && self.modules_is_marked_as_referenced(file, aliases, other, seen) }) } @@ -1218,31 +1332,17 @@ impl Checker<'_, '_> { is_ambient: bool, ) { let (hir, files) = (self.hir(cx.file), self.files()); - let scope = self.bound(cx.file).export_scope[x.idx()]; let ExportSpec { local: name, - local_pos: start, type_only, .. } = hir[s]; - // `export { "a" }`: not a name. - if scope.is_none() || matches!(cx.text.get(start as usize), Some(b'"' | b'\'')) { + // `checkAliasSymbol`: `resolveAlias`. `export { "a" }`: not a name. + let Some((location, scope, resolved)) = self.check_target_of_export_specifier(cx.file, s) + else { return; - } - // `PropertyNameOrName` - let location = match hir.property_name(hir.node(s)) { - Node::NONE => hir.name(hir.node(s)), - written => written, }; let all = SymFlags::VALUE | SymFlags::TYPE | SymFlags::NAMESPACE; - let message = self.get_cannot_find_name_diagnostic_for_name(cx.file, location, name); - // `getTargetOfExportSpecifier` - let is_found = files.resolve_name(cx.file, scope, name, all).is_some(); - if !is_found { - self.on_failed_to_resolve_symbol(cx.file, location, None, scope, name, all, message); - } else if resolves_to_umd_global(files, cx.file, scope, name, all) { - self.error(cx.file, location, 2686, &[Arg::Atom(name)]); - } let is_global = files .resolve_name(cx.file, scope, name, all | SymFlags::ALIAS) .is_some_and(|found| { @@ -1257,13 +1357,14 @@ impl Checker<'_, '_> { // `markLinkedReferences`: not where nothing is emitted, nor when exports are preserved // verbatim. // `markIdentifierAliasReferenced`: a name that is not elided is resolved again, as a value. - if !is_found + if resolved.is_none() && !is_ambient && !type_only && !hir[x].type_only && !files.options.verbatim_module_syntax { let meaning = SymFlags::VALUE | SymFlags::EXPORT_VALUE; + let message = self.get_cannot_find_name_diagnostic_for_name(cx.file, location, name); self.on_failed_to_resolve_symbol( cx.file, location, None, scope, name, meaning, message, ); diff --git a/src/sema/check/errors_names_and_exports.rs b/src/sema/check/errors_names_and_exports.rs index bc889dbcd1cd..e848a3444f34 100644 --- a/src/sema/check/errors_names_and_exports.rs +++ b/src/sema/check/errors_names_and_exports.rs @@ -40,6 +40,7 @@ impl Checker<'_, '_> { || unchecked.contain(start) || self.cached_by_emit.contains(&e) || self.is_never_checked(start) + || self.is_computed_name_never_checked(file, e) { continue; } @@ -183,7 +184,9 @@ impl Checker<'_, '_> { if name.is_none() || hir.is_missing(name) { return b"(Missing)".to_vec(); } - let written = self.source_text(file, hir.start(name), self.end_of_node(file, name)); + let (start, end) = (hir.start(name), self.end_of_node(file, name)); + let start = super::spans::start_of_error_range(hir, start, end); + let written = self.source_text(file, start, end); // The text of the default library is not retained. match hir.text(name) { text if written.is_empty() && text.is_some() => self.atoms().bytes(text).to_vec(), @@ -374,7 +377,7 @@ pub(super) fn fully_qualified_name( ) -> Vec { // `combineValueAndTypeSymbols`: `result.Parent` is that of the value symbol, if it has one. if let Some((alias, true)) = c.files().alias_of_transient_symbol(sym) - && let Some((object, name, _)) = c.symbol_from_variable(alias) + && let Some((object, name)) = c.symbol_from_variable(alias) && let (qualified, true) = fully_qualified_name_of_property(c, object, name) { return qualified; diff --git a/src/sema/check/errors_operators.rs b/src/sema/check/errors_operators.rs index b2ed5c056772..a6b26b12f52a 100644 --- a/src/sema/check/errors_operators.rs +++ b/src/sema/check/errors_operators.rs @@ -3,18 +3,16 @@ //! //! Follows `checkAssignmentOperator` for `=`, the pattern grammar part of //! `checkDestructuringAssignment`, `checkAssertion`, `checkSatisfiesExpression`, -//! `checkTemplateExpression`, `resolveTaggedTemplateExpression`, `checkInstanceOfExpression`, -//! `resolveInstanceofExpression` and `checkYieldExpression` of TypeScript 7.0.2's checker.go, and +//! `checkTemplateExpression`, `resolveTaggedTemplateExpression`, `checkInstanceOfExpression` and +//! `checkYieldExpression` of TypeScript 7.0.2's checker.go, and //! `checkGrammarBigIntLiteral` and `checkGrammarBindingElement` of its grammarchecks.go. -//! -//! Must be called after `check_assignments`: 2412 replaces the 2322 reported there. use super::*; use crate::bind::Parent; use crate::resolve::ScriptTarget; impl Checker<'_, '_> { - /// `a = b`. Runs after `check_assignments`, whose diagnostics it replaces. + /// `check_plain_assignment` for every `a = b`. pub(super) fn check_x_operators(&mut self, file: FileId) { let (hir, bound) = (self.hir(file), self.bound(file)); if hir.kind == FileKind::Declaration { @@ -159,7 +157,8 @@ pub(super) fn why_no_reference( } /// `a = b`, as in `checkBinaryLikeExpression`: the reference check of `checkAssignmentOperator`. -/// `check_assignments` compares the types. A pattern is handled by `checkDestructuringAssignment`. +/// `check_plain_assignment_operator` compares the types. A pattern is handled by +/// `checkDestructuringAssignment`. fn check_plain_assignment(c: &mut Checker<'_, '_>, file: FileId, target: ExprId) { let hir = c.hir(file); if !matches!(hir[target].kind, ExprKind::Object(_) | ExprKind::Array(_)) @@ -226,8 +225,8 @@ pub(super) fn check_tagged_template(c: &mut Checker<'_, '_>, file: FileId, call: // ───────────────────────────── `instanceof` and `in` ───────────────────────────── -/// `checkInstanceOfExpression`, `resolveInstanceofExpression` for `e`, which is `left instanceof -/// right`: 2358 2359, and 2860 2861 from checking against the signature it resolves to. +/// `checkInstanceOfExpression` for `e`, which is `left instanceof right`: 2358 2861, and 2359 2860 +/// from `resolveInstanceofExpression`. Only there are the members of the type of `right` asked for. pub(super) fn check_instance_of_expression( c: &mut Checker<'_, '_>, file: FileId, @@ -235,36 +234,10 @@ pub(super) fn check_instance_of_expression( left: ExprId, right: ExprId, ) { - let (l, r) = (c.type_of_expr(file, left), c.type_of_expr(file, right)); + let l = c.type_of_expr(file, left); if !c.is_any(l) && c.is_all_assignable_to_primitives(l) { c.error(file, c.hir(file).child(left), 2358, &[]); } - if c.is_any(r) { - return; - } - let Some(method) = c.symbol_has_instance_method_of_object_type(r) else { - let function = c.global_ref(known::Function, &[]); - if c.signatures(r, false).is_empty() - && c.signatures(r, true).is_empty() - && !c.is_subtype(r, function) - { - c.error(file, c.hir(file).child(right), 2359, &[]); - } - return; - }; - // The constraint of a type parameter may not have been resolved. - let apparent_right = c.apparent_type(r); - if c.is_any(apparent_right) { - return; - } - let apparent = c.apparent_type(method); - if c.is_any(method) { - return; - } - let signatures = c.signatures(apparent, false); - if signatures.is_empty() { - return; - } let resolved = c.resolved_signature(file, e); let resolved = c.with_return_type(resolved); c.report_call_resolution(file, e); diff --git a/src/sema/check/errors_order.rs b/src/sema/check/errors_order.rs index b8b687b06e18..44a2fc72bf37 100644 --- a/src/sema/check/errors_order.rs +++ b/src/sema/check/errors_order.rs @@ -53,7 +53,7 @@ impl Checker<'_, '_> { |m: &&Member| matches!(m.kind, MemberKind::Property | MemberKind::StaticBlock); let places = Places::new(hir.members.iter().filter(is_place).map(|m| m.loc)); for &e in index.of(ExprTag::Dot) { - if !bound.is_unchecked(e.idx()) { + if !bound.is_unchecked(e.idx()) && !self.is_never_checked(hir[e].pos) { let may_be_in_place = places.contain(hir[e].pos); self.check_property_not_used_before_declaration(file, e, may_be_in_place); } @@ -395,7 +395,8 @@ impl Checker<'_, '_> { let mut ty = None; for block in blocks { let ty = *ty.get_or_insert_with(|| self.type_of_member_declaration(file, member)); - if self.is_assigned_in_constructor(file, hir[block].func, name, ty) { + let key = super::flow::AccessKey::Name(name); + if self.is_assigned_in_constructor(file, hir[block].func, key, ty) { return true; } } @@ -442,8 +443,15 @@ impl Checker<'_, '_> { } /// `prop.ValueDeclaration` - fn value_declaration_of(&self, prop: &Prop) -> Option<(FileId, Node)> { - let (file, decl) = self.value_declaration_of_prop(prop)?; + fn value_declaration_of(&mut self, prop: &Prop) -> Option<(FileId, Node)> { + let (mut file, mut decl) = self.value_declaration_of_prop(prop)?; + // `mergeSymbol`, `SetValueDeclaration`: a late bound declaration takes the place of an + // assignment, and of nothing else. + if matches!(decl, Decl::ThisProperty(_) | Decl::Expando(_)) + && let Some(&PropSource::Symbol(sym)) = Self::value_declaration(prop) + { + (file, decl) = self.value_declaration_of_property(sym)?; + } Some((file, self.hir(file).node(decl))) } diff --git a/src/sema/check/errors_overloads.rs b/src/sema/check/errors_overloads.rs index 238f42fae6a4..28f6c4abd5bc 100644 --- a/src/sema/check/errors_overloads.rs +++ b/src/sema/check/errors_overloads.rs @@ -19,11 +19,10 @@ const EXPORT_TYPE: u8 = 2; const EXPORT_NAMESPACE: u8 = 4; impl Checker<'_, '_> { - /// The checks that `checkFunctionOrMethodDeclaration`, `checkConstructorDeclaration`, - /// `checkClassLikeDeclaration` and the callers of `checkExportsOnMergedDeclarations` run on the - /// declarations of `file`. - pub(super) fn check_overloads(&mut self, file: FileId) { - let (hir, bound, files) = (self.hir(file), self.bound(file), self.files()); + /// The checks that `checkClassLikeDeclaration` and the callers of + /// `checkExportsOnMergedDeclarations` run on the declarations of `file`. + pub(super) fn check_merged_symbols(&mut self, file: FileId) { + let (hir, bound) = (self.hir(file), self.bound(file)); if hir.has_errors || hir.kind == FileKind::Json { return; } @@ -34,54 +33,94 @@ impl Checker<'_, '_> { if symbol.export_symbol.is_some() && symbol.decls.len() > 1 { self.check_exports_on_merged_declarations(file, id); } - let first = symbol.decls.iter().find_map(|&decl| { - let function = self.function_of_declaration((file, decl))?; - Some((decl, function)) - }); - let class = symbol - .decls - .iter() - .find(|decl| matches!(decl, Decl::Class(_))); - if first.is_none() && class.is_none() { - continue; + if (symbol.decls.iter()).any(|decl| matches!(decl, Decl::Class(_))) { + self.check_function_or_constructor_symbol_at(file, id, None); } - // A single declaration with a body: no error is possible. - if let Some((_, function)) = first - && symbol.decls.len() == 1 - && !symbol.flags.contains(SymFlags::MERGED) - && symbol.name != known::computed - && has_body(&hir[function]) + } + } + + /// `checkFunctionOrMethodDeclaration`, from `hasBindableName`, and `checkConstructorDeclaration`: + /// `checkFunctionOrConstructorSymbol` for `node.LocalSymbol()` and for the symbol of `decl`. + pub(super) fn check_function_or_constructor_symbols_of(&mut self, file: FileId, decl: Decl) { + let (hir, bound) = (self.hir(file), self.bound(file)); + let symbol = bound.symbol_of_declaration(decl); + if hir.has_errors || hir.kind == FileKind::Json || symbol.is_none() { + return; + } + if let Decl::Fn(function) = decl + && bound.symbols[symbol.idx()].parent.is_some() + && let Some(scope) = bound.scope_of_declaration(hir, decl).some() + && let Some(local) = bound.lookup(bound.scopes[scope.idx()].locals, hir[function].name) + && bound.symbols[local.idx()].export_symbol == symbol + { + self.check_function_or_constructor_symbol_at(file, local, Some(decl)); + } + self.check_function_or_constructor_symbol_at(file, symbol, Some(decl)); + } + + /// `checkFunctionOrConstructorSymbol` for the symbol `id` of `file`. "Only check the symbol + /// once": a function checks it if it is the first of its functions in `file`. `at`: the + /// function. `None`: a class, which comes after all the functions. + fn check_function_or_constructor_symbol_at( + &mut self, + file: FileId, + id: SymbolId, + at: Option, + ) { + let (hir, bound, files) = (self.hir(file), self.bound(file), self.files()); + let symbol = &bound.symbols[id.idx()]; + let first = symbol.decls.iter().find_map(|&decl| { + let function = self.function_of_declaration((file, decl))?; + Some((decl, function)) + }); + if at.is_some() && first.map(|first| first.0) != at { + return; + } + // A single declaration with a body: no error is possible. + if let Some((_, function)) = first + && symbol.decls.len() == 1 + && !symbol.flags.contains(SymFlags::MERGED) + && symbol.name != known::computed + && has_body(&hir[function]) + { + return; + } + let sym = files.sym(file, id); + // Checked once per symbol, whichever of its parts the loop over the symbols reaches. A + // function has the symbol it declares, which is a part: never the clone they are merged into. + if at.is_none() && sym.file == file && sym.id != id { + return; + } + // The declarations in other files ask when those files are checked. + let is_checked_by_function = match first { + None => false, + // `hasBindableName` + Some((Decl::Member(m), _)) + if symbol.name == known::computed + && self.declared_member_name(file, hir[m].key).is_none() => { - continue; - } - let sym = files.sym(file, id); - // Checked once per symbol, regardless of which of its parts is reached. - if sym.file == file && sym.id != id { - continue; - } - // The declarations in other files ask when those files are checked. - let is_checked_by_function = match first { - None => false, - // `hasBindableName` - Some((Decl::Member(m), _)) - if symbol.name == known::computed - && self.declared_member_name(file, hir[m].key).is_none() => - { - false - } - // "ignore javascript function declarations so that redeclaring a function in a JS file is not reported as a duplicate", but - // "run check on export symbol" (`symbol.Parent != nil`). A constructor has a parent. - Some(_) => !hir.is_js || symbol.parent.is_some(), - }; - // `checkClassLikeDeclaration` checks `getSymbolOfDeclaration(node)`, which is not the - // local symbol of an export. FOR SPEED: no error is possible in what is no function. - let is_checked_by_class = class.is_some_and(|&decl| { - files.flags(sym).contains(SymFlags::FUNCTION) - && files.sym(file, bound.symbol_of_declaration(decl)) == sym - }); - if is_checked_by_function || is_checked_by_class { - self.check_function_or_constructor_symbol(sym); + false } + // "ignore javascript function declarations so that redeclaring a function in a JS file is not reported as a duplicate", but + // "run check on export symbol" (`symbol.Parent != nil`). A constructor has a parent. + Some(_) => !hir.is_js || symbol.parent.is_some(), + }; + // `checkClassLikeDeclaration` checks `getSymbolOfDeclaration(node)`, which is not the + // local symbol of an export. FOR SPEED: no error is possible in what is no function. + let class = symbol + .decls + .iter() + .find(|decl| matches!(decl, Decl::Class(_))); + let is_checked_by_class = class.is_some_and(|&decl| { + files.flags(sym).contains(SymFlags::FUNCTION) + && files.sym(file, bound.symbol_of_declaration(decl)) == sym + }); + let is_checked = match at { + Some(_) => is_checked_by_function, + None => !is_checked_by_function && is_checked_by_class, + }; + if is_checked { + self.check_function_or_constructor_symbol(sym); } } diff --git a/src/sema/check/errors_signatures.rs b/src/sema/check/errors_signatures.rs index bfaafbfbb0d0..b50755be3986 100644 --- a/src/sema/check/errors_signatures.rs +++ b/src/sema/check/errors_signatures.rs @@ -188,7 +188,7 @@ impl Checker<'_, '_> { .some() .filter(|&f| { hir[f].ret == node - && (self.parenthesized_types_around(file, node, hir[f].start)) + && (self.parenthesized_types_around(file, node, 0)) .next() .is_none() && matches!( diff --git a/src/sema/check/errors_small.rs b/src/sema/check/errors_small.rs index 4d5ce4cd90b8..c0065846ec3d 100644 --- a/src/sema/check/errors_small.rs +++ b/src/sema/check/errors_small.rs @@ -14,6 +14,8 @@ use crate::bind::{ pub(super) enum SymbolAtLocation<'p> { /// `getMergedSymbol` of a symbol of the binder. Symbol(Sym), + /// What `instantiateSymbol` made of that member for the table of that type. + Instantiated(Sym, TypeId), /// A property that has no symbol of the binder. The properties of a mapped type have one /// source. Property(&'p PropSource<'p>, Atom), @@ -28,6 +30,17 @@ pub(super) enum SymbolAtLocation<'p> { Anonymous(FileId, Node), } +impl SymbolAtLocation<'_> { + /// The symbol, if the binder or the merge of the files made it. + pub(super) fn of_binder(&self) -> Option { + if let SymbolAtLocation::Symbol(symbol) = *self { + Some(symbol) + } else { + None + } + } +} + /// `a == b` fn is_same_symbol<'p>(a: &Option>, b: &Option>) -> bool { a == b && !matches!(a, Some(SymbolAtLocation::IndexOfSeveral)) @@ -409,6 +422,11 @@ impl<'p> Checker<'p, '_> { NodeData::Expr(e) => match hir[e].kind { // `getSymbolOfNameOrPropertyAccessExpression` ExprKind::Ident(name) => { + if hir.is_jsx_tag_name(node) + && let Some(prop_name) = self.jsx_intrinsic_tag_name(file, e) + { + return self.get_intrinsic_tag_symbol(file, parent, prop_name); + } let symbol = self.resolve_identifier(file, e, name, true).ok()??; Some(SymbolAtLocation::Symbol(files.canonical(symbol))) } @@ -427,9 +445,29 @@ impl<'p> Checker<'p, '_> { } _ => None, }, - // `IsRightSideOfQualifiedNameOrPropertyAccess`: `links.resolvedSymbol` of the access. - NodeData::Part(Part::Name, access) => match hir.data(access) { - NodeData::Expr(e) => self.symbol_at_name(file, e), + NodeData::Part(Part::Name, named) => match hir.data(named) { + NodeData::Expr(e) => match hir[e].kind { + // `checkNewTargetMetaProperty(parent).symbol`. The `meta` of `import.meta` is a + // symbol of its own, and no other meta property has one. + ExprKind::NewTarget(name) if self.atoms().bytes(name) == b"target" => { + let ty = self.type_of_expr(file, e); + self.symbol_of_type(ty) + } + // `IsRightSideOfQualifiedNameOrPropertyAccess`: `links.resolvedSymbol` of the + // access. + _ => self.symbol_at_name(file, e), + }, + // `name.Parent.Kind == KindTypePredicate` + NodeData::Type(predicate) => { + let TypeNodeKind::Predicate { param, .. } = hir[predicate].kind else { + return None; + }; + let meaning = SymFlags::FUNCTION_SCOPED_VARIABLE; + let scope = bound.type_scope[predicate.idx()]; + let symbol = files.resolve_name(file, scope, param, meaning)?; + let symbol = files.resolve_alias_as(symbol, meaning)?; + Some(SymbolAtLocation::Symbol(files.canonical(symbol))) + } _ => None, }, // `{ name: local }`: the property of the type of the pattern. @@ -487,8 +525,11 @@ impl<'p> Checker<'p, '_> { Origin::ClassStatic(symbol) | Origin::Function(symbol) | Origin::EnumObject(symbol) - | Origin::Module(symbol) - | Origin::Namespace { module: symbol, .. } => SymbolAtLocation::Symbol(symbol), + | Origin::Module(symbol) => SymbolAtLocation::Symbol(symbol), + // `cloneTypeAsModuleType` + Origin::Namespace { + originating_import, .. + } => SymbolAtLocation::Symbol(self.module_clone(originating_import)), Origin::ObjectLiteral(file, e, ..) | Origin::WidenedLiteral(file, e, ..) => { SymbolAtLocation::Anonymous(file, self.hir(file).node(e)) } @@ -499,21 +540,96 @@ impl<'p> Checker<'p, '_> { }, TypeData::Fns { ref decls, .. } => { let &(file, function) = decls.first()?; - SymbolAtLocation::Anonymous(file, self.hir(file).node(function)) + // A name in a function expression resolves to `node.Symbol`. + match self.bound(file).fn_symbol[function.idx()].some() { + Some(symbol) => SymbolAtLocation::Symbol(files.sym(file, symbol)), + None => SymbolAtLocation::Anonymous(file, self.hir(file).node(function)), + } } + TypeData::Synth(ref shape) => match (shape.symbol, shape.symbol_declared_at) { + (Some(symbol), _) => SymbolAtLocation::Symbol(symbol), + // `getSpreadType`, `getWidenedTypeOfObjectLiteral` + (None, Some((file, _, literal))) if literal.is_some() => { + SymbolAtLocation::Anonymous(file, self.hir(file).node(literal)) + } + _ => return None, + }, _ => return None, }) } /// `getPropertyOfType(ty, name)` fn symbol_of_property(&mut self, ty: TypeId, name: Atom) -> Option> { - let (prop, _) = self.get_property_of_type(ty, name)?; + let (prop, mapper) = self.get_property_of_type(ty, name)?; Some(match prop.source { - PropSource::Symbol(symbol) => SymbolAtLocation::Symbol(self.files().canonical(symbol)), + PropSource::Symbol(symbol) => { + let symbol = self.files().canonical(symbol); + let mapper = self.compose(prop.mapper, mapper); + match self.instantiation_of_member(symbol, mapper) { + Some(instantiation) => SymbolAtLocation::Instantiated(symbol, instantiation), + None => SymbolAtLocation::Symbol(symbol), + } + } ref source => SymbolAtLocation::Property(source, name), }) } + /// `instantiateSymbolTable`: the instantiation of the class, the interface or the type literal + /// that declares `member` whose table has an instantiated symbol for it, where `mapper` is + /// what a property with that symbol is read with. `None`: the table has `member` itself. The + /// type of `member` counts as resolved by then. + pub(super) fn instantiation_of_member( + &mut self, + member: Sym, + mapper: MapperId, + ) -> Option { + if mapper == MapperId::IDENTITY { + return None; + } + let files = self.files(); + let parent = files.parent_of_symbol(member)?; + let declared = if (files.flags(parent)).intersects(SymFlags::CLASS | SymFlags::INTERFACE) { + let this = self.intern(TypeData::ThisParam(parent)); + let declared = self.declared_type(parent); + self.type_with_this_argument(declared, this) + } else if let Some(&(file, Decl::TypeLiteral(node))) = files.decls_of(parent).first() { + self.type_from_node(file, node) + } else { + return None; + }; + let instantiation = self.instantiate(declared, mapper); + // `slices.Equal(typeParameters, typeArguments)`, `mappingThisOnly && isThisless(symbol)` + if instantiation == declared || self.is_thisless_for_this_mapper(member) { + return None; + } + // `instantiateSymbol`: nothing has asked for `links.writeType` of a setter. + let is_setter = (self.flags_of_property(member)).contains(SymFlags::SET_ACCESSOR); + let ty = self.type_of_symbol(member); + (is_setter || self.could_contain_type_variables(ty)).then_some(instantiation) + } + + /// `getIntrinsicTagSymbol` of `node`, whose tag has the name `prop_name`. `None`: + /// `unknownSymbol`. `check_jsx` reports. + fn get_intrinsic_tag_symbol( + &mut self, + file: FileId, + node: Node, + prop_name: Atom, + ) -> Option> { + let intrinsic_elements_type = self.jsx_type(file, node, known::IntrinsicElements)?; + if let Some(intrinsic_prop) = self.symbol_of_property(intrinsic_elements_type, prop_name) { + return Some(intrinsic_prop); + } + let index_symbol = self.get_applicable_index_symbol(intrinsic_elements_type, prop_name); + if index_symbol.is_some() { + return index_symbol; + } + // `getTypeOfPropertyOrIndexSignatureOfType` + let members = self.members_for_index_infos(intrinsic_elements_type)?; + self.applicable_index_info_for_name(&members, prop_name)?; + self.symbol_of_type(intrinsic_elements_type) + } + /// `links.resolvedSymbol` of the property access or the qualified name `e`, as /// `getSymbolOfNameOrPropertyAccessExpression` leaves it. fn symbol_at_name(&mut self, file: FileId, e: ExprId) -> Option> { @@ -525,8 +641,17 @@ impl<'p> Checker<'p, '_> { if let Some(property) = self.symbol_of_property(ty, name) { return Some(property); } - // `getApplicableIndexSymbol`: there is one only if an index signature is declared. - let ty = self.reduced(receiver); + self.get_applicable_index_symbol(receiver, name) + } + + /// `getApplicableIndexSymbol(ty, getStringLiteralType(name))`: there is one only if an index + /// signature is declared. + fn get_applicable_index_symbol( + &mut self, + ty: TypeId, + name: Atom, + ) -> Option> { + let ty = self.reduced(ty); let ty = self.apparent_type(ty); let members = self.members(ty)?; let info = self.applicable_index_info_for_name(&members, name)?; @@ -618,12 +743,16 @@ impl<'p> Checker<'p, '_> { if enums.len() < 2 { return; } - // "Only perform this check once per symbol": where `getSymbolOfDeclaration` first answers - // it. The local symbol of an exported declaration lists that declaration too. - let first_checked = enums - .iter() - .find(|&&(f, e)| files.sym(f, self.bound(f).enum_symbol[e.idx()]) == enum_symbol); - if first_checked != Some(&(file, e)) { + // "Only perform this check once per symbol": at the first declaration that + // `checkSourceElement` reaches and `getSymbolOfDeclaration` answers it for. The local + // symbol of an exported declaration lists that declaration too. + let name_pos = self.hir(file)[e].name_pos; + let is_checked_before = |&(f, other): &(FileId, EnumId)| { + files.sym(f, self.bound(f).enum_symbol[other.idx()]) == enum_symbol + && self.is_checked_no_later_than(f, file) + && (f != file || self.hir(f)[other].name_pos < name_pos) + }; + if enums.iter().any(is_checked_before) { return; } let enum_is_const = self.hir(file)[e].flags.contains(Flags::CONST); diff --git a/src/sema/check/errors_statements.rs b/src/sema/check/errors_statements.rs index a776d2619ef2..8984dd94f332 100644 --- a/src/sema/check/errors_statements.rs +++ b/src/sema/check/errors_statements.rs @@ -1,7 +1,7 @@ //! Statements, and checks of variable and property declarations. //! //! * `with`: 1101 1300 2410. Misplaced `return`: 1108 18041. `if (x);`: 1313. Statements in ambient -//! contexts: 1036. +//! contexts: 1036 1183. //! * Assignment targets of `for`-`in` and `for`-`of`: 2405 2406 2780, 2487 2781, 1106. //! * `catch`: 1196 1197 2492. //! * Where `await`, `for await` and `await using` are allowed: 1308 1375 1378 2524 18037, 1103 1431 @@ -116,6 +116,22 @@ pub(super) fn is_with_statement(hir: &File, s: StmtId) -> bool { && is_word_at(&hir.text, hir[s].start as usize, b"with") } +/// The parts of `range` that are in none of `holes`. +fn parts_outside(range: (u32, u32), mut holes: Vec<(u32, u32)>) -> Vec<(u32, u32)> { + holes.sort_unstable(); + let (mut from, mut parts) = (range.0, Vec::new()); + for (start, end) in holes { + if from < start { + parts.push((from, start)); + } + from = from.max(end); + } + if from < range.1 { + parts.push((from, range.1)); + } + parts +} + /// The diagnostics of binder.go. The binder visits every node, whether or not the checker does. Not /// 1184: the binder only reports it for `export as namespace`, and wherever it is reported here it /// comes from the checker (`reportObviousModifierErrors`). @@ -149,37 +165,57 @@ const HAS_REPORTED_STATEMENT_IN_AMBIENT_CONTEXT: u8 = 4; impl Checker<'_, '_> { // ───────────────────────────── statements ───────────────────────────── - /// `checkGrammarStatementInAmbientContext`: 1036, once in each block. + /// `checkGrammarStatementInAmbientContext` #[inline] pub(super) fn check_grammar_statement_in_ambient_context( &mut self, file: FileId, s: StmtId, ) -> bool { - self.has_ambient_context && self.check_grammar_statement_in_ambient_file(file, s) + self.has_ambient_context + && self.check_grammar_statement_in_ambient_file(file, self.hir(file).node(s)) + } + + /// The same for the block that is the body of `func`. + #[inline] + pub(super) fn check_grammar_function_body_in_ambient_context( + &mut self, + file: FileId, + func: FnId, + ) { + if self.has_ambient_context { + let hir = self.hir(file); + self.check_grammar_statement_in_ambient_file(file, hir.body(hir.node(func))); + } } - /// The same, in a file in which something is ambient. - fn check_grammar_statement_in_ambient_file(&mut self, file: FileId, s: StmtId) -> bool { + /// The same, in a file in which something is ambient: 1183 for the body of a function, which + /// covers its statements, and 1036 once in every other block. + fn check_grammar_statement_in_ambient_file(&mut self, file: FileId, node: Node) -> bool { let hir = self.hir(file); - let node = hir.node(s); if !hir.is_ambient(node) { return false; } + let has_reported = HAS_REPORTED_STATEMENT_IN_AMBIENT_CONTEXT; let parent = hir.parent(node); - if !matches!( - hir.kind(parent), - Kind::Block | Kind::ModuleBlock | Kind::SourceFile - ) - // 1183 is reported on the body of a function, which covers its statements. - || hir.kind(hir.parent(parent)).is_function_like() - || self.has_node_check_flag(parent, HAS_REPORTED_STATEMENT_IN_AMBIENT_CONTEXT) - || !self.grammar_error_at((file, hir[s].start, 0), 1036, &[]) - { + let parent_kind = hir.kind(parent); + let (links, code) = + if parent_kind.is_function_like() && !self.has_node_check_flag(node, has_reported) { + (node, 1183) + } else if matches!( + parent_kind, + Kind::Block | Kind::ModuleBlock | Kind::SourceFile + ) && !self.has_node_check_flag(parent, has_reported) + { + (parent, 1036) + } else { + return false; + }; + // `grammarErrorOnFirstToken` + if !self.grammar_error_at(self.place_of_token(file, hir.start(node)), code, &[]) { return false; } - *self.node_check_flags.entry(parent).or_default() |= - HAS_REPORTED_STATEMENT_IN_AMBIENT_CONTEXT; + *self.node_check_flags.entry(links).or_default() |= has_reported; true } @@ -286,6 +322,20 @@ impl Checker<'_, '_> { } } + /// After `checkSourceFile`: `checkExternalImportOrExportDeclaration` reports 1141 for a module + /// specifier that is not a string literal, and returns. + pub(super) fn never_check_specifier_expressions(&self, file: FileId) { + let hir = self.hir(file); + let required = hir.import_equals.iter().map(|import| import.expression); + let specifiers = hir.specifier_expressions.iter().copied(); + for specifier in specifiers.chain(required.filter(|e| e.is_some())) { + self.never_check( + self.start_of(file, specifier), + self.end_of_expr(file, specifier), + ); + } + } + /// `never_check` for `range`, the range of `node`, which `checkSourceFile` does not visit, /// without the nodes below `node` that a query has computed a type from /// (`checkDeclarationInitializer`, `getTypeFromTypeNode`, `getTypeOfSymbol`, the flow analysis). @@ -297,16 +347,8 @@ impl Checker<'_, '_> { ) { let mut visited = Vec::new(); self.ranges_visited_by_queries(file, node, &mut visited); - visited.sort_unstable(); - let mut from = range.0; - for (visited_start, visited_end) in visited { - if from < visited_start { - self.never_check(from, visited_start); - } - from = from.max(visited_end); - } - if from < range.1 { - self.never_check(from, range.1); + for (from, to) in parts_outside(range, visited) { + self.never_check(from, to); } } @@ -815,25 +857,55 @@ impl Checker<'_, '_> { self.check_type_assignable_to(source, target, Some(at), Some(2850 + u32::from(is_await))); } + /// The ranges of `expressions_cached_discarding`, where every check of `checkExpression` has + /// reported in vain, without the nodes that `checkDeferredNodes` has checked since. + fn ranges_checked_discarding(&self, file: FileId) -> Vec<(u32, u32)> { + let mut ranges = Vec::new(); + for &e in &self.expressions_cached_discarding { + if !self.is_deferred_node.contains(&e) { + let mut deferred = Vec::new(); + self.ranges_of_deferred_nodes(file, self.hir(file).node(e), &mut deferred); + let range = (self.start_of(file, e), self.end_of_expr(file, e)); + ranges.extend(parts_outside(range, deferred)); + } + } + ranges + } + + /// The ranges of the outermost nodes below `node` that `checkNodeDeferred` was called with. + fn ranges_of_deferred_nodes(&self, file: FileId, node: Node, found: &mut Vec<(u32, u32)>) { + let hir = self.hir(file); + hir.for_each_child(node, &mut |child| { + let expression = match hir.data(child) { + NodeData::Expr(e) => e, + NodeData::Prop(p) => hir[p].value, + _ => ExprId::NONE, + }; + if self.is_deferred_node.contains(&expression) { + found.push((hir.start(child), self.end_of_node(file, child))); + } else { + self.ranges_of_deferred_nodes(file, child, found); + } + false + }); + } + /// Removes the diagnostics reported inside ranges that `checkSourceFile` never visits. Parser and binder diagnostics stay. Runs /// after all passes. pub(super) fn remove_diagnostics_in_unchecked_ranges(&mut self, file: FileId) { let hir = self.hir(file); - // `checkExternalImportOrExportDeclaration` reports 1141 for a module specifier that is not - // a string literal, and returns. - for &specifier in &hir.specifier_expressions { - self.never_check( - self.start_of(file, specifier), - self.end_of_expr(file, specifier), - ); - } - let never_checked = self.never_checked.borrow(); + let discarded = self.ranges_checked_discarding(file); + let never_checked = [&self.never_checked.borrow()[..], &discarded[..]].concat(); if !never_checked.is_empty() { self.reported.retain(|d| { !(never_checked.iter()).any(|&(from, to)| (from..to).contains(&d.start)) || d.by_emit - // Reported on the node that is not checked. - || matches!(d.code, 1136 | 1141) + || d.by_another_node + // Reported on the node that is not checked, by the check of its parent only. + || matches!(d.code, 1039 | 1136 | 1141 | 1254) + // Likewise, on an element of a heritage clause. A class below it can have them. + || matches!(d.code, 1174 | 2499 | 2500) + && never_checked.iter().any(|&(from, _)| from == d.start) || is_binder_diagnostic(d.code) || hir.diagnostics.iter().any(|parsed| { !matches!( diff --git a/src/sema/check/errors_type_nodes.rs b/src/sema/check/errors_type_nodes.rs index b67ee785c2fc..271c40cdbdc6 100644 --- a/src/sema/check/errors_type_nodes.rs +++ b/src/sema/check/errors_type_nodes.rs @@ -75,7 +75,7 @@ pub(super) fn start_of_type(hir: &hir::File, node: TypeNodeId) -> u32 { loop { let end = skip_trivia_back(text, at); if !matches!(text[..end].last(), Some(b'(' | b'|' | b'&')) { - return at as u32; + return hir.skip_trivia_of_node_at(at as u32); } at = end - 1; } @@ -188,8 +188,8 @@ impl Checker<'_, '_> { if flags.contains(ElemFlags::VARIADIC) { let ty = self.type_from_node(file, elem.ty); if !self.is_array_like(ty) { - let at = (file, elem.start, self.end_of_tuple_elem(file, e)); - self.error_at(at, 2574, &[]); + let start = hir.skip_trivia_of_node_at(elem.start); + self.error_at((file, start, self.end_of_tuple_elem(file, e)), 2574, &[]); break; } if self.is_array(ty) @@ -214,8 +214,8 @@ impl Checker<'_, '_> { } else { continue; }; - let at = (file, elem.start, self.end_of_tuple_elem(file, e)); - self.grammar_error_at(at, code, &[]); + let start = hir.skip_trivia_of_node_at(elem.start); + self.grammar_error_at((file, start, self.end_of_tuple_elem(file, e)), code, &[]); break; } } diff --git a/src/sema/check/errors_unused.rs b/src/sema/check/errors_unused.rs index af5e7a3385c5..3ffd81e3954c 100644 --- a/src/sema/check/errors_unused.rs +++ b/src/sema/check/errors_unused.rs @@ -135,7 +135,23 @@ impl Checker<'_, '_> { |s| matches!(s.kind, StmtKind::Return(e) if e.is_some() && u.is_in_unchecked_return(e)), ); let index = self.exprs_by_kind(file); - u.note_references(&index); + self.note_identifiers(file, &index, &mut u); + u.note_references(); + self.note_module_references(file, &mut u); + self.note_unresolved_type_references(file, &mut u); + self.note_untyped_signature_parameters(file, &mut u); + for &(of, scope, name, meaning) in &self.tracked_names { + if of == file { + let bit = if meaning == SymFlags::TYPE { + TYPE + } else if meaning == SymFlags::NAMESPACE { + NAMESPACE + } else { + VALUE + }; + u.note_name(scope, name, meaning, bit); + } + } let links = &self.p.symbol_reference_links; for (i, kinds) in u.referenced.iter_mut().enumerate() { let id = SymbolId(i as u32); @@ -183,6 +199,183 @@ impl Checker<'_, '_> { self.check_unused_identifiers(&u); } + /// `getResolvedSymbol` of every identifier that is checked: `Resolve` with `isUse`. + fn note_identifiers(&mut self, file: FileId, index: &ExprsByKind, u: &mut Unused) { + let (hir, bound) = (self.hir(file), self.bound(file)); + for &e in index.of(ExprTag::Ident) { + let i = e.idx(); + let symbol = bound.expr_symbol[i]; + if symbol.is_none() + || u.referenced[symbol.idx()] & VALUE != 0 + || bound.is_unchecked(i) + || u.is_unchecked(e) + || u.is_write_only(e) + || u.is_inside_declaration_of(e, symbol) + { + continue; + } + // `checkVariableLikeDeclaration` only validates the alias that `const x = require("m")` declares. It does not check the + // initializer, so it does not resolve the callee. + if let Parent::Expr(call) = bound.expr_parent[i] + && call.is_some() + && let Parent::VarInit(d) = bound.expr_parent[call.idx()] + && matches!(hir[hir[d].pat].kind, PatKind::Ident(_)) + && bound.required_by(hir, hir[d].pat).is_some() + { + continue; + } + if bound.symbols[symbol.idx()] + .flags + .intersects(SymFlags::VALUE) + { + u.referenced[symbol.idx()] |= VALUE; + continue; + } + // `getSymbol` finds an alias only if its target has the meaning. Otherwise the search + // goes on in the outer scopes. + let ExprKind::Ident(name) = hir[e].kind else { + continue; + }; + let Ok(at) = bound.alias_idents.binary_search_by_key(&e, |alias| alias.0) else { + continue; + }; + let found = u.resolve_use_with( + bound.alias_idents[at].1, + name, + SymFlags::VALUE | SymFlags::EXPORT_VALUE, + &mut |held, meaning| self.get_symbol(held, meaning), + ); + if let Some(found) = found { + u.note_use(found, VALUE); + } + } + // `containsArgumentsReference` passes the name of a declaration to it too, and no such + // name is a write (`IsWriteOnlyAccess`). + for &(_, scope, local) in bound.names_resolved_for_arguments.iter() { + if local.is_some() { + let meaning = SymFlags::VALUE | SymFlags::EXPORT_VALUE; + u.note_name(scope, known::arguments, meaning, VALUE); + } + } + } + + /// `resolveQualifiedName` where it reports that `names` do not resolve. Unless it suggests + /// another spelling (2724), it asks `tryGetQualifiedNameAsValue`, which resolves the first name + /// as a value with `isUse`. + fn note_qualified_name_as_value( + &mut self, + file: FileId, + u: &mut Unused, + scope: ScopeId, + names: Span, + meaning: SymFlags, + ) { + let hir = self.hir(file); + if hir.kind(hir.node(names)) != Kind::QualifiedName + || self + .resolve_entity_name(file, scope, names, meaning, true) + .is_some() + { + return; + } + let reported = self.reported.len(); + self.check_qualified_name(file, scope, names, meaning); + if self.reported.drain(reported..).any(|d| d.code != 2724) { + u.note_name(scope, hir[names.at(0)].text, SymFlags::VALUE, VALUE); + } + } + + /// `note_qualified_name_as_value` for the type references `a.b` whose type is the error type. + fn note_unresolved_type_references(&mut self, file: FileId, u: &mut Unused) { + let (hir, bound) = (self.hir(file), self.bound(file)); + for (i, node) in hir.types.iter().enumerate() { + let TypeNodeKind::Ref { name, .. } = node.kind else { + continue; + }; + if name.len() < 2 || bound.is_unchecked_type(i) { + continue; + } + let known = self + .p + .type_node_types + .get(&self.task, &(file, TypeNodeId(i as u32))); + if known.is_some_and(|ty| self.is_error_type(ty)) { + let scope = bound.type_scope[i]; + self.note_qualified_name_as_value(file, u, scope, name, SymFlags::TYPE); + } + } + } + + /// The lookups of the `a` of every `import x = a.b`. + fn note_module_references(&mut self, file: FileId, u: &mut Unused) { + let (hir, bound) = (self.hir(file), self.bound(file)); + // `canCollectSymbolAliasAccessibilityData` + let marks_aliases = !self.p.files.options.verbatim_module_syntax; + let mut aliases = None; + for (i, import) in hir.import_equals.iter().enumerate() { + let ImportEqualsTarget::Entity(names) = import.target else { + continue; + }; + if matches!(bound.stmt_parent[import.stmt.idx()], Parent::None) { + continue; + } + let scope = bound.import_equals_scope[i]; + if !u.note_module_reference(scope, names) { + continue; + } + let any = SymFlags::VALUE | SymFlags::TYPE | SymFlags::NAMESPACE; + self.note_qualified_name_as_value(file, u, scope, names, any); + // `markAliasSymbolAsReferenced`: `getResolvedSymbol(a)` if the target is a value, which + // `unknownSymbol` is. Any other is exported by a namespace that is a value itself, and + // `note_module_reference` has looked that up as a value. + if !marks_aliases || hir[names.at(0)].text == known::empty { + continue; + } + let aliases = aliases.get_or_insert_with(|| self.symbols_of_alias_declarations(file)); + let x = ImportEqualsId(i as u32); + if self.modules_is_marked_as_referenced(file, aliases, x, &mut Vec::new()) { + let meaning = SymFlags::VALUE | SymFlags::EXPORT_VALUE; + u.note_name(scope, hir[names.at(0)].text, meaning, VALUE); + } + } + } + + /// `reportImplicitAny`, `case KindParameter`: `resolveName` of the name as a type, with `isUse`, + /// also where the message is only a suggestion. `checkParameter` requests the type of every + /// parameter, and `getTypeForVariableLikeDeclaration` has none for one of a signature that has + /// neither an annotation nor an initializer. + fn note_untyped_signature_parameters(&self, file: FileId, u: &mut Unused) { + let (hir, bound) = (self.hir(file), self.bound(file)); + if hir.is_js && !self.is_check_js(file) { + return; + } + for (i, param) in hir.params.iter().enumerate() { + if param.ty.is_some() || param.default.is_some() { + continue; + } + let Some(name) = self.identifier_of_signature_parameter(file, ParamId(i as u32)) else { + continue; + }; + let signature = &bound.fns[bound.param_fn[i].idx()]; + let within = match signature.owner { + FnOwner::Type(node) => node, + FnOwner::Member(m) => match bound.member_owner[m.idx()] { + MemberOwner::TypeLiteral(node) => node, + _ => TypeNodeId::NONE, + }, + _ => TypeNodeId::NONE, + }; + if signature.scope.is_none() + || self.is_type_node_keyword(name) + || within.is_some() && bound.is_unchecked_type(within.idx()) + || u.is_never_checked(param.pos) + { + continue; + } + u.note_name(signature.scope, name, SymFlags::TYPE, TYPE); + } + } + /// `RuntimeSyntaxTransformer` writes `x || (x = {})` for an enum or a namespace `x`. In a file /// that is emitted as CommonJS, `visitAssignmentExpression` asks for the exports of the target /// (`getExports`, `GetReferencedImportDeclaration`). Its original is the name of the @@ -339,59 +532,66 @@ impl Checker<'_, '_> { } } - /// The names that `evaluate(e, location)` resolves. It visits what `evaluate` visits. + /// The names that `evaluate(e, location)` resolves. It visits what `evaluate` visits, but the + /// initializer of a constant only once. fn note_evaluated(&mut self, file: FileId, u: &mut Unused, e: ExprId, location: Location) { - if self.is_stack_low() { - return; - } let hir = self.hir(file); - match hir[e].kind { - ExprKind::Unary { - op: - UnOp::Plus | UnOp::Minus | UnOp::BitNot | UnOp::Not | UnOp::PreInc | UnOp::PreDec, - operand, - } => self.note_evaluated(file, u, operand, location), - ExprKind::Binary { left, right, .. } - | ExprKind::Assign { - target: left, - value: right, - .. - } => { - self.note_evaluated(file, u, left, location); - self.note_evaluated(file, u, right, location); - } - // `evaluateTemplateExpression` stops at the first span without a value. - ExprKind::Template { exprs } => { - for span in hir.ids(exprs) { - self.note_evaluated(file, u, span, location); - if self.evaluate(file, span, location).value.is_none() { - break; + let mut constants = smallvec::SmallVec::<[VarDeclId; 4]>::new(); + let mut operands = smallvec::SmallVec::<[(ExprId, Location); 8]>::new(); + operands.push((e, location)); + while let Some((e, location)) = operands.pop() { + match hir[e].kind { + ExprKind::Unary { + op: + UnOp::Plus + | UnOp::Minus + | UnOp::BitNot + | UnOp::Not + | UnOp::PreInc + | UnOp::PreDec, + operand, + } => operands.push((operand, location)), + ExprKind::Binary { left, right, .. } + | ExprKind::Assign { + target: left, + value: right, + .. + } => operands.extend([(left, location), (right, location)]), + // `evaluateTemplateExpression` stops at the first span without a value. + ExprKind::Template { exprs } => { + for span in hir.ids(exprs) { + operands.push((span, location)); + if self.evaluate(file, span, location).value.is_none() { + break; + } } } - } - ExprKind::Index { obj, index, .. } => { - if is_string_literal_like(hir, index) - && !is_parenthesized(hir, index) - && !is_parenthesized(hir, obj) - && is_property_access_entity_name_expression(hir, obj) - { - self.note_qualified_name(file, u, obj); + ExprKind::Index { obj, index, .. } => { + if is_string_literal_like(hir, index) + && !is_parenthesized(hir, index) + && !is_parenthesized(hir, obj) + && is_property_access_entity_name_expression(hir, obj) + { + self.note_qualified_name(file, u, obj); + } } - } - ExprKind::Dot { .. } if is_property_access_entity_name_expression(hir, e) => { - self.note_qualified_name(file, u, e); - } - // The initializer of a constant. - ExprKind::Ident(_) => { - if let Some(symbol) = self.resolve_entity_name_expression(file, e, SymFlags::VALUE) - && let Some((of, d)) = self.constant_variable_declaration(symbol, location) - && of == file - { - let location = Location::Variable(of, d); - self.note_evaluated(file, u, hir[d].init, location); + ExprKind::Dot { .. } if is_property_access_entity_name_expression(hir, e) => { + self.note_qualified_name(file, u, e); } + // The initializer of a constant. + ExprKind::Ident(_) => { + if let Some(symbol) = + self.resolve_entity_name_expression(file, e, SymFlags::VALUE) + && let Some((of, d)) = self.constant_variable_declaration(symbol, location) + && of == file + && !constants.contains(&d) + { + constants.push(d); + operands.push((hir[d].init, Location::Variable(of, d))); + } + } + _ => {} } - _ => {} } } @@ -464,10 +664,22 @@ impl Checker<'_, '_> { continue; }; from = host.start as usize; - let scope = host.scope; let comments = jsdoc_comment_ranges(text, &host, hir.is_js); - let links = (comments.iter()).flat_map(|&(start, end)| jsdoc_links(text, start, end)); - for names in links { + let is_stack_low = || self.is_stack_low(); + let links = (comments.iter()) + .flat_map(|&(start, end)| jsdoc_links(text, start, end, &is_stack_low)); + // `checkSourceElementWorker` visits the comments of `jsdoc` and of `jsdoc.Tags`. + let mut names_of_links = Vec::new(); + for link in links { + match link.nested_tag { + None => names_of_links.push((host.scope, link.name)), + Some(tag) => { + let scopes = u.scopes_of_reparsed_tag(tag as u32).into_iter(); + names_of_links.extend(scopes.map(|scope| (scope, link.name.clone()))); + } + } + } + for (scope, names) in names_of_links { let Some(first) = atoms.lookup(&names[0]) else { continue; }; @@ -583,7 +795,7 @@ impl Checker<'_, '_> { .. } = s.kind && !matches!(bound.stmt_parent[i], Parent::None) - && !hir.is_in_with(s.start) + && !u.is_never_checked(s.start) && let StmtKind::Expr(target) = hir[left].kind && matches!(hir[target].kind, ExprKind::Object(_) | ExprKind::Array(_)) { @@ -592,42 +804,52 @@ impl Checker<'_, '_> { self.note_destructured(file, u, target, source, None); } } - // `const { x } = o`: `checkVariableLikeDeclaration`. The name of every binding element is - // looked up in the destructured type, even the name of a rest element or of an array - // pattern element. + // `const { x } = o`: `checkVariableLikeDeclaration`. `PropertyNameOrName` of every binding + // element is looked up in the destructured type, even that of a rest element or of an + // array pattern element. let unchecked = self.unchecked_jsdoc_types(file); for i in 0..hir.pats.len() { - if hir.is_in_with(hir.pats[i].pos) + if u.is_never_checked(hir.pats[i].pos) || matches!(bound.pat_parent[i], PatParent::None) || unchecked.contain(hir.pats[i].pos) { continue; } + let mut read = Vec::new(); match hir.pats[i].kind { PatKind::Object(props) => { - let whole = self.type_of_pat(file, PatId(i as u32)); for p in props.iter() { - let name = match hir[hir[p].value].kind { - PatKind::Ident(name) if hir[p].is_rest => Some(name), - _ => self.member_name(file, hir[p].key), - }; - if let Some(name) = name.filter(|&n| is_private(n)) { - self.note_property(file, u, whole, name, None, None); + // "variable renaming in function type notation is confusing": it returns + // before it asks for the type of the parent. + if self.is_renamed_binding_element(file, p) + && self.returns_before_type_of_symbol(file, hir[p].value) + { + continue; } + let name = match (hir[p].key, hir[hir[p].value].kind) { + (PropKey::None, PatKind::Ident(name)) => Some(name), + (key, _) => self.member_name(file, key), + }; + read.extend(name.filter(|&n| is_private(n))); } } PatKind::Array(elems) => { - let whole = self.type_of_pat(file, PatId(i as u32)); for element in elems.iter() { if let PatKind::Ident(name) = hir[hir[element].pat].kind && is_private(name) { - self.note_property(file, u, whole, name, None, None); + read.push(name); } } } _ => {} } + if !read.is_empty() { + let whole = self.type_of_pat(file, PatId(i as u32)); + for name in read { + self.note_property(file, u, whole, name, None, None); + } + } } } @@ -672,7 +894,8 @@ impl Checker<'_, '_> { if !matches!(hir[p].kind, PropKind::Init | PropKind::Shorthand) { continue; } - let Some(name) = self.member_name(file, hir[p].key) else { + let (key, pos) = (hir[p].key, hir[p].pos); + let Some(name) = self.try_get_name_from_property_name(file, key, pos) else { continue; }; self.note_property(file, u, source, name, None, from_this); @@ -1015,14 +1238,10 @@ fn jsdoc_tag_takes_brace(name: &[u8]) -> bool { | b"augments" | b"extends" | b"this" - | b"arg" - | b"argument" - | b"param" | b"return" | b"returns" | b"template" | b"type" - | b"typedef" | b"satisfies" | b"exception" | b"throws" @@ -1042,6 +1261,9 @@ enum JSDocToken { Asterisk, OpenBrace, CloseBrace, + OpenBracket, + CloseBracket, + Equals, Dot, Backtick, /// `tokenIsIdentifierOrKeyword` @@ -1095,11 +1317,79 @@ struct JSDocScannerState { has_preceding_line_break: bool, } -/// `parseJSDocComment` for the comment of `source` from `start` to `end`: the names of each -/// `{@link a.b}`, `{@linkcode a.b}` and `{@linkplain a.b}` that has a name. A missing name is -/// empty. -fn jsdoc_links(source: &[u8], start: usize, end: usize) -> Vec>> { +/// A `JSDocLink`, `JSDocLinkCode` or `JSDocLinkPlain` that has a name. +struct JSDocLink<'a> { + /// `a.b`. A missing name is empty. + name: Vec>, + /// The position of the tag whose comment it is in, if that tag is nested in another tag and so + /// is not among `jsdoc.Tags`. + nested_tag: Option, +} + +/// What is kept of a `JSDocTypeExpression`. +#[derive(Copy, Clone)] +struct JSDocTypeExpression { + /// `isObjectOrObjectArrayTypeReference(node.Type())` + is_object_or_object_array: bool, + /// `node.End()` + end: usize, +} + +/// What `tryParseChildTag` returns. +enum JSDocChildTag<'a> { + /// `JSDocParameterTag`, `JSDocPropertyTag`: `node.Name()`. + ParameterOrProperty(Vec>), + /// `JSDocTypeTag`: its type, if that is in braces. + Type(Option), + /// `JSDocTemplateTag`, `JSDocThisTag` + Other, +} + +/// `propertyLikeParse` +const PROPERTY: u8 = 1; +const PARAMETER: u8 = 2; +const CALLBACK_PARAMETER: u8 = 4; + +/// `isObjectOrObjectArrayTypeReference` for the type that `text` starts with: the source after the +/// `{` of a type expression. +fn is_object_or_object_array_type_reference(text: &[u8]) -> bool { + // `Scan` with `skipJSDocLeadingAsterisks`: the start and the end of the token after `at`. + let token_after = |at: usize| { + let mut start = skip_trivia(text, at); + if text.get(start) == Some(&b'*') + && (at..start).any(|i| super::spans::line_break_len(text, i) != 0) + { + start = skip_trivia(text, start + 1); + } + (start, token_end(text, start, false)) + }; + let (start, mut end) = token_after(0); + if !matches!(&text[start..end], b"Object" | b"object") { + return false; + } + // `parsePostfixTypeOrHigher` + loop { + let (open, after_open) = token_after(end); + let (close, after_close) = token_after(after_open); + match (text.get(open), text.get(close)) { + (None | Some(b'}'), _) => return true, + (Some(b'['), Some(b']')) => end = after_close, + _ => return false, + } + } +} + +/// `parseJSDocComment` for the comment of `source` from `start` to `end`: each `{@link a.b}`, +/// `{@linkcode a.b}` and `{@linkplain a.b}` that has a name. +fn jsdoc_links<'a>( + source: &'a [u8], + start: usize, + end: usize, + is_stack_low: &'a dyn Fn() -> bool, +) -> Vec> { let mut parser = JSDocParser { + is_stack_low, + is_out_of_stack: false, text: &source[..end - 2], scanner: JSDocScannerState { token: JSDocToken::Other, @@ -1109,6 +1399,7 @@ fn jsdoc_links(source: &[u8], start: usize, end: usize) -> Vec has_preceding_line_break: false, }, links: Vec::new(), + nested_tag: None, }; parser.parse_jsdoc_comment_worker(start); parser.links @@ -1116,13 +1407,27 @@ fn jsdoc_links(source: &[u8], start: usize, end: usize) -> Vec /// The part of jsdoc.go, of TypeScript's parser, that finds the links in a JSDoc comment. struct JSDocParser<'a> { + /// `Checker::is_stack_low` + is_stack_low: &'a dyn Fn() -> bool, + /// See `is_too_deep`. + is_out_of_stack: bool, /// The source, up to the `*/` of the comment. text: &'a [u8], scanner: JSDocScannerState, - links: Vec>>, + links: Vec>, + /// `JSDocLink::nested_tag` of the links in the comment of the tag that is being parsed. + nested_tag: Option, } impl<'a> JSDocParser<'a> { + /// Whether a tag is not to be parsed inside another one. Every cycle of calls in this parser goes through + /// `parse_jsdoc_signature` or `try_parse_child_tag`, one level for each tag of a run of `@overload`, `@callback` or + /// `@param {Object} a`. Once the stack has been low, each further tag of the comment would get as deep again. + fn is_too_deep(&mut self) -> bool { + self.is_out_of_stack |= (self.is_stack_low)(); + self.is_out_of_stack + } + /// `nextTokenJSDoc`, `ScanJSDocToken` fn next_token_jsdoc(&mut self) -> JSDocToken { let (text, start) = (self.text, self.scanner.pos); @@ -1145,6 +1450,9 @@ impl<'a> JSDocParser<'a> { Some(b'*') => JSDocToken::Asterisk, Some(b'{') => JSDocToken::OpenBrace, Some(b'}') => JSDocToken::CloseBrace, + Some(b'[') => JSDocToken::OpenBracket, + Some(b']') => JSDocToken::CloseBracket, + Some(b'=') => JSDocToken::Equals, Some(b'.') => JSDocToken::Dot, Some(b'`') => JSDocToken::Backtick, Some(b'\\') => match lexer::peek_unicode_escape(text, start) { @@ -1232,7 +1540,13 @@ impl<'a> JSDocParser<'a> { let pos = token_end(text, start, false); let token = match text.get(start) { None => JSDocToken::EndOfFile, + Some(b'@') => JSDocToken::At, + Some(b'{') => JSDocToken::OpenBrace, Some(b'}') => JSDocToken::CloseBrace, + Some(b'[') => JSDocToken::OpenBracket, + Some(b']') => JSDocToken::CloseBracket, + Some(b'*') if pos == start + 1 => JSDocToken::Asterisk, + Some(b'=') if pos == start + 1 => JSDocToken::Equals, Some(b'.') if pos == start + 1 => JSDocToken::Dot, Some(b'#') if text.get(start + 1) != Some(&b'!') => JSDocToken::PrivateIdentifier, Some(b'0'..=b'9') => JSDocToken::Other, @@ -1262,6 +1576,26 @@ impl<'a> JSDocParser<'a> { super::spans::unescaped_identifier(&self.text[self.scanner.start..self.scanner.pos]) } + /// `mark` + fn mark(&self) -> (JSDocScannerState, usize) { + (self.scanner, self.links.len()) + } + + /// `rewind` + fn rewind(&mut self, state: (JSDocScannerState, usize)) { + self.scanner = state.0; + self.links.truncate(state.1); + } + + /// `parseOptional` + fn parse_optional(&mut self, token: JSDocToken) -> bool { + let is_next = self.scanner.token == token; + if is_next { + self.next_token(); + } + is_next + } + /// `parseOptionalJsdoc` fn parse_optional_jsdoc(&mut self, token: JSDocToken) -> bool { let is_next = self.scanner.token == token; @@ -1398,29 +1732,294 @@ impl<'a> JSDocParser<'a> { if seen_line_break { indent } else { 0 } } - /// `parseTag`. Of the syntax of a tag, only a type in braces right after its name is passed - /// over. The rest is read as its comment. - fn parse_tag(&mut self, margin: usize) { + /// `parseTag`. Returns whether it is a `JSDocReturnTag`. + fn parse_tag(&mut self, margin: usize) -> bool { let start = self.scanner.start; self.next_token_jsdoc(); - // `parseJSDocIdentifierName` - let mut tag_name = Cow::default(); - if self.scanner.token == JSDocToken::Identifier { - tag_name = self.token_value(); - self.next_token_jsdoc(); + let tag_name = self.parse_jsdoc_identifier_name(); + let indent_text = self.skip_whitespace_or_asterisk(); + match &*tag_name { + b"arg" | b"argument" | b"param" => { + self.parse_parameter_or_property_tag(start, PARAMETER, margin); + } + b"typedef" => self.parse_typedef_tag(start, margin, indent_text), + b"callback" => self.parse_callback_tag(start, margin, indent_text), + b"overload" => self.parse_overload_tag(start, margin, indent_text), + _ => self.parse_tag_without_children(start, &tag_name, margin, indent_text), } + matches!(&*tag_name, b"return" | b"returns") + } + + /// The parsers of the tags that have no tags nested in them. Of their syntax, only a type in + /// braces right after the name is passed over. The rest is read as the comment. + fn parse_tag_without_children( + &mut self, + start: usize, + tag_name: &[u8], + margin: usize, + indent_text: usize, + ) { + if self.scanner.token == JSDocToken::OpenBrace && jsdoc_tag_takes_brace(tag_name) { + self.parse_jsdoc_type_expression(); + } + self.parse_trailing_tag_comments(start, self.scanner.full_start, margin, indent_text); + } + + /// `parseJSDocIdentifierName`. A missing name is empty. + fn parse_jsdoc_identifier_name(&mut self) -> Cow<'a, [u8]> { + if self.scanner.token != JSDocToken::Identifier { + return Cow::default(); + } + let text = self.token_value(); + self.next_token_jsdoc(); + text + } + + /// `parseJSDocEntityName` + fn parse_jsdoc_entity_name(&mut self) -> Vec> { + let mut entity = Vec::new(); + loop { + entity.push(self.parse_jsdoc_identifier_name()); + // "Note that y[] is accepted as an entity name" + if self.parse_optional(JSDocToken::OpenBracket) { + self.parse_optional(JSDocToken::CloseBracket); + } + if !self.parse_optional(JSDocToken::Dot) { + return entity; + } + } + } + + /// `parseJSDocTypeExpression` at a `{`. The type is passed over, not parsed. + fn parse_jsdoc_type_expression(&mut self) -> JSDocTypeExpression { + let inside = self.scanner.pos; + // No type starts with `@`, and `parseTagComments` ends at it: it starts a tag. + let end = match self.text.get(inside) { + Some(b'@') => inside, + _ => (closing_bracket_after(self.text, inside) as usize + 1).min(self.text.len()), + }; + self.reset_pos(end); + self.next_token_jsdoc(); + let written = &self.text[inside..]; + JSDocTypeExpression { + is_object_or_object_array: is_object_or_object_array_type_reference(written), + end, + } + } + + /// `tryParseTypeExpression` + fn try_parse_type_expression(&mut self) -> Option { + self.skip_whitespace_or_asterisk(); + (self.scanner.token == JSDocToken::OpenBrace).then(|| self.parse_jsdoc_type_expression()) + } + + /// `parseBracketNameInPropertyAndParamTag` + fn parse_bracket_name_in_property_and_param_tag(&mut self) -> Vec> { + let open = self.scanner.start; + let is_bracketed = self.parse_optional_jsdoc(JSDocToken::OpenBracket); + if is_bracketed { + self.skip_whitespace(); + } + let is_backquoted = self.parse_optional_jsdoc(JSDocToken::Backtick); + let name = self.parse_jsdoc_entity_name(); + if is_backquoted { + self.parse_optional(JSDocToken::Backtick); + } + if is_bracketed { + self.skip_whitespace(); + // "May have an optional default, e.g. '[foo = 42]'". It is passed over, not parsed. + if self.scanner.token == JSDocToken::Equals { + let after = end_of_brackets(self.text, open); + self.reset_pos(after.map_or(self.text.len(), |after| after - 1)); + self.next_token(); + } + self.parse_optional(JSDocToken::CloseBracket); + } + name + } + + /// `parseParameterOrPropertyTag`, `parseNestedTypeLiteral`. Returns `node.Name()`. + fn parse_parameter_or_property_tag( + &mut self, + start: usize, + target: u8, + indent: usize, + ) -> Vec> { + let mut type_expression = self.try_parse_type_expression(); + self.skip_whitespace_or_asterisk(); + let name = self.parse_bracket_name_in_property_and_param_tag(); let indent_text = self.skip_whitespace_or_asterisk(); - if self.scanner.token == JSDocToken::OpenBrace && jsdoc_tag_takes_brace(&tag_name) { - let inside = self.scanner.pos; - // No type starts with `@`, and `parseTagComments` ends at it: it starts a tag. - let after = match self.text.get(inside) { - Some(b'@') => inside, - _ => closing_bracket_after(self.text, inside) as usize + 1, - }; - self.reset_pos(after.min(self.text.len())); + if type_expression.is_none() { + let state = self.scanner; + let is_at_link = self.parse_jsdoc_link_prefix(); + self.scanner = state; + if !is_at_link { + type_expression = self.try_parse_type_expression(); + } + } + self.parse_trailing_tag_comments(start, self.scanner.full_start, indent, indent_text); + if type_expression.is_some_and(|it| it.is_object_or_object_array) { + while self + .parse_child_parameter_or_property_tag(target, indent, Some(&name)) + .is_some() + {} + } + name + } + + /// `parseJSDocTypeNameWithNamespace`, or a missing name. + fn parse_jsdoc_type_name_with_namespace(&mut self) { + while self.scanner.token == JSDocToken::Identifier { self.next_token_jsdoc(); + if !self.parse_optional_jsdoc(JSDocToken::Dot) { + break; + } } - self.parse_trailing_tag_comments(start, self.scanner.full_start, margin, indent_text); + } + + /// `parseTypedefTag` + fn parse_typedef_tag(&mut self, start: usize, indent: usize, indent_text: usize) { + let type_expression = self.try_parse_type_expression(); + self.skip_whitespace_or_asterisk(); + self.parse_jsdoc_type_name_with_namespace(); + // `fullName.End()` + let mut end = self.scanner.full_start; + self.skip_whitespace(); + let has_comment = self.parse_tag_comments(indent, None); + if type_expression.is_none_or(|it| it.is_object_or_object_array) { + let mut has_children = false; + let mut child_type_tag = None; + while let Some(child) = + self.parse_child_parameter_or_property_tag(PROPERTY, indent, None) + { + has_children = true; + if let JSDocChildTag::Type(Some(written)) = child { + child_type_tag.get_or_insert(written); + } + } + // `typeExpression.End()` + if has_children { + end = match child_type_tag { + Some(written) if !written.is_object_or_object_array => written.end, + _ => self.scanner.full_start, + }; + } + } + if !has_comment { + self.parse_trailing_tag_comments(start, end, indent, indent_text); + } + } + + /// `parseJSDocSignature`, `parseCallbackTagParameters` + fn parse_jsdoc_signature(&mut self, indent: usize) { + while self + .parse_child_parameter_or_property_tag(CALLBACK_PARAMETER, indent, None) + .is_some() + {} + if self.is_too_deep() { + return; + } + let state = self.mark(); + let outer = self.nested_tag.replace(self.scanner.start); + if !(self.parse_optional_jsdoc(JSDocToken::At) + && self.scanner.token == JSDocToken::At + && self.parse_tag(indent)) + { + self.rewind(state); + } + self.nested_tag = outer; + } + + /// `parseCallbackTag`, which goes on like `parseOverloadTag` after the name. + fn parse_callback_tag(&mut self, start: usize, indent: usize, indent_text: usize) { + self.parse_jsdoc_type_name_with_namespace(); + self.parse_overload_tag(start, indent, indent_text); + } + + /// `parseOverloadTag` + fn parse_overload_tag(&mut self, start: usize, indent: usize, indent_text: usize) { + self.skip_whitespace(); + let has_comment = self.parse_tag_comments(indent, None); + self.parse_jsdoc_signature(indent); + if !has_comment { + self.parse_trailing_tag_comments(start, self.scanner.full_start, indent, indent_text); + } + } + + /// `parseChildParameterOrPropertyTag`, and the `rewind` of its callers if there is none. + /// `name`: of the tag that a `@param` or a `@property` has to name a property of. + fn parse_child_parameter_or_property_tag( + &mut self, + target: u8, + indent: usize, + name: Option<&[Cow<'a, [u8]>]>, + ) -> Option> { + let state = self.mark(); + let mut can_parse_tag = true; + let mut seen_asterisk = false; + let child = loop { + match self.next_token_jsdoc() { + JSDocToken::At if can_parse_tag && self.can_follow_jsdoc_at() => { + break self.try_parse_child_tag(target, indent); + } + JSDocToken::At => seen_asterisk = false, + JSDocToken::NewLineTrivia => { + can_parse_tag = true; + seen_asterisk = false; + } + JSDocToken::Asterisk => { + can_parse_tag &= !seen_asterisk; + seen_asterisk = true; + } + JSDocToken::Identifier => can_parse_tag = false, + JSDocToken::EndOfFile => break None, + _ => {} + } + }; + // `textsEqual(name, child.Name().AsQualifiedName().Left)` + let child = child.filter(|child| match (child, name) { + (JSDocChildTag::ParameterOrProperty(child), Some(name)) => { + child.split_last().is_some_and(|(_, left)| left == name) + } + _ => true, + }); + if child.is_none() { + self.rewind(state); + } + child + } + + /// `tryParseChildTag` + fn try_parse_child_tag(&mut self, target: u8, indent: usize) -> Option> { + if self.is_too_deep() { + return None; + } + let start = self.scanner.full_start; + self.next_token_jsdoc(); + let tag_name = self.parse_jsdoc_identifier_name(); + let indent_text = self.skip_whitespace_or_asterisk(); + let fits = match &*tag_name { + b"prop" | b"property" => PROPERTY, + b"arg" | b"argument" | b"param" => PARAMETER | CALLBACK_PARAMETER, + _ => 0, + }; + let outer = self.nested_tag.replace(start); + let child = match &*tag_name { + // `parseTypeTag` without an indent leaves the comment to the `@typedef`. + b"type" if target == PROPERTY => { + Some(JSDocChildTag::Type(self.try_parse_type_expression())) + } + b"template" | b"this" => { + self.parse_tag_without_children(start, &tag_name, indent, indent_text); + Some(JSDocChildTag::Other) + } + _ if target & fits != 0 => Some(JSDocChildTag::ParameterOrProperty( + self.parse_parameter_or_property_tag(start, target, indent), + )), + _ => None, + }; + self.nested_tag = outer; + child } /// `parseTrailingTagComments` for the tag that starts at `start`. `indent_text`: the length of @@ -1435,16 +2034,21 @@ impl<'a> JSDocParser<'a> { if indent_text == 0 { margin += end - start; } - self.parse_tag_comments(margin, indent_text.saturating_sub(margin)); + self.parse_tag_comments(margin, Some(indent_text.saturating_sub(margin))); } - /// `parseTagComments`. `initial_margin`: the length of that text. - fn parse_tag_comments(&mut self, mut indent: usize, initial_margin: usize) { - let mut state = JSDocState::SawAsterisk; + /// `parseTagComments`. `initial_margin`: the length of that text. Returns whether there is a + /// comment. + fn parse_tag_comments(&mut self, mut indent: usize, initial_margin: Option) -> bool { + let mut state = match initial_margin { + Some(_) => JSDocState::SawAsterisk, + None => JSDocState::BeginningOfLine, + }; let mut backtick_count = 0; let mut in_fenced_code_block = false; let mut margin = None; - if initial_margin != 0 { + let mut has_comment = false; + if let Some(initial_margin @ 1..) = initial_margin { margin = Some(indent); indent += initial_margin; } @@ -1479,6 +2083,7 @@ impl<'a> JSDocParser<'a> { JSDocToken::OpenBrace if !in_fenced_code_block => { state = JSDocState::SavingComments; is_pushed = !self.parse_jsdoc_link(); + has_comment |= !is_pushed; } JSDocToken::At | JSDocToken::OpenBrace => { state = JSDocState::saving(in_fenced_code_block); @@ -1502,6 +2107,10 @@ impl<'a> JSDocParser<'a> { if is_pushed { margin.get_or_insert(indent); indent += token_len; + // `removeTrailingWhitespace` + let is_white_space = lexer::is_white_space_single_line; + has_comment |= lexer::end_of_run(self.text, self.scanner.start, is_white_space) + < self.scanner.pos; } if state.is_saving() { self.next_jsdoc_comment_text_token(state == JSDocState::SavingBackticks); @@ -1509,6 +2118,7 @@ impl<'a> JSDocParser<'a> { self.next_token_jsdoc(); } } + has_comment } /// `parseJSDocLink`. Returns whether there is a link at the current token, a `{`. @@ -1522,7 +2132,8 @@ impl<'a> JSDocParser<'a> { self.skip_whitespace(); let name = self.parse_jsdoc_link_name(); if !name.is_empty() { - self.links.push(name); + let nested_tag = self.nested_tag; + self.links.push(JSDocLink { name, nested_tag }); } while !matches!( self.scanner.token, @@ -1550,11 +2161,22 @@ impl<'a> JSDocParser<'a> { // `ReScanHashToken` self.scanner.pos = self.scanner.start + 1; self.next_token_jsdoc(); - name.push(self.parse_identifier_name()); + name.push(self.parse_identifier()); } name } + /// `parseIdentifier`, outside a `yield` and an `await` context. A reserved word is left where + /// it is, and the name is missing. + fn parse_identifier(&mut self) -> Cow<'a, [u8]> { + if self.scanner.token == JSDocToken::Identifier + && super::errors_declaration_emit::is_reserved_word(&self.token_value()) + { + return Cow::default(); + } + self.parse_identifier_name() + } + /// `parseIdentifierName` fn parse_identifier_name(&mut self) -> Cow<'a, [u8]> { if self.scanner.token != JSDocToken::Identifier { @@ -1642,41 +2264,14 @@ pub(super) fn is_thisless_type(hir: &hir::File, t: TypeNodeId) -> bool { impl Unused<'_, '_> { // ───────────────────────────── references ───────────────────────────── - fn note_references(&mut self, index: &ExprsByKind) { + fn note_references(&mut self) { let (hir, bound) = (self.hir, self.bound); - for &e in index.of(ExprTag::Ident) { - let i = e.idx(); - let symbol = bound.expr_symbol[i]; - if symbol.is_none() - || self.referenced[symbol.idx()] & VALUE != 0 - || bound.is_unchecked(i) - || self.is_unchecked(e) - || self.is_write_only(e) - || self.is_inside_declaration_of(e, symbol) - { - continue; - } - // `checkVariableLikeDeclaration` only validates the alias that `const x = require("m")` declares. It does not check the - // initializer, so it does not resolve the callee. - if let Parent::Expr(call) = bound.expr_parent[i] - && call.is_some() - && let Parent::VarInit(d) = bound.expr_parent[call.idx()] - && matches!(hir[hir[d].pat].kind, PatKind::Ident(_)) - && bound.required_by(hir, hir[d].pat).is_some() - { - continue; - } - self.referenced[symbol.idx()] |= VALUE; - } for i in 0..hir.types.len() { let scope = bound.type_scope[i]; let TypeNodeKind::Ref { name, .. } = hir.types[i].kind else { continue; }; - if bound.is_unchecked_type(i) - || hir.is_in_with(hir.types[i].pos) - || self.is_never_checked(hir.types[i].pos) - { + if bound.is_unchecked_type(i) || self.is_never_checked(hir.types[i].pos) { continue; } let Some(first) = hir.texts(name).next() else { @@ -1697,20 +2292,16 @@ impl Unused<'_, '_> { if matches!(bound.stmt_parent[i], Parent::None) { continue; } - match s.kind { - // `export { a }` references `a` with any meaning. - StmtKind::ExportNamed(id) if !hir[id].has_module_specifier => { - let scope = bound.export_scope[id.idx()]; - for item in hir[id].items.iter() { - self.note_name(scope, hir[item].local, SymFlags::all(), ALL); - } - } - StmtKind::ImportEquals(id) => { - if let ImportEqualsTarget::Entity(names) = hir[id].target { - self.note_module_reference(bound.import_equals_scope[id.idx()], names); - } + // `export { a }` references `a` with any meaning, past + // `checkGrammarModuleElementContext`. + if let StmtKind::ExportNamed(id) = s.kind + && !hir[id].has_module_specifier + && matches!(bound.stmt_parent[i], Parent::File | Parent::Module(_)) + { + let scope = bound.export_scope[id.idx()]; + for item in hir[id].items.iter() { + self.note_name(scope, hir[item].local, SymFlags::all(), ALL); } - _ => {} } } // `export default I`, `export = I`: a type is accepted too. @@ -1721,6 +2312,7 @@ impl Unused<'_, '_> { StmtKind::ExportDefault(_) | StmtKind::ExportAssign(_) ) && let ExprKind::Ident(name) = hir[e].kind + && !self.is_never_checked(hir[e].pos) { self.note_name(scope, name, SymFlags::all(), ALL); } @@ -1779,15 +2371,17 @@ impl Unused<'_, '_> { scope } - /// The statement, member, parameter, function type or variable declaration that has `at` in - /// the trivia before its first token, where its JSDoc comments are (`withJSDoc`). Those are the - /// nodes with comments that are passed to `checkSourceElement`. + /// The statement, member, parameter, function type, named tuple member or variable declaration + /// that has `at` in the trivia before its first token, where its JSDoc comments are + /// (`withJSDoc`). Those are the nodes with comments that are passed to `checkSourceElement`. fn jsdoc_host_at(&self, at: u32) -> Option { let (hir, bound) = (self.hir, self.bound); // The range of a node is empty if the parser did not record it. let follows = |loc: TextRange, start: u32| loc.end != 0 && (loc.pos..start).contains(&at); + // A query visits a declared name without its declaration. + let is_visited = |start: u32| !self.is_never_checked(at) && !self.is_never_checked(start); let host = |loc: TextRange, start: u32, scope: ScopeId, owns_trailing_comments: bool| { - (scope.is_some() && !hir.is_in_with(start)).then_some(JSDocHost { + (scope.is_some() && is_visited(start)).then_some(JSDocHost { loc, start, scope, @@ -1797,6 +2391,18 @@ impl Unused<'_, '_> { let is_checked = |i: usize| !matches!(bound.stmt_parent[i], Parent::None); let mut statements = hir.stmts.iter().enumerate(); if let Some((i, s)) = statements.find(|&(i, s)| follows(s.loc, s.start) && is_checked(i)) { + let is_host = match s.kind { + // `parseExpressionOrLabeledStatement`, `hasParen`: the comments belong to the + // `ParenthesizedExpression` alone, which `checkSourceElement` never visits. + StmtKind::Expr(_) => hir.text.get(s.start as usize) != Some(&b'('), + // `checkTryStatement` and `checkCatchClause` call `checkBlock` themselves. + StmtKind::Block(_) => !matches!(bound.stmt_parent[i], Parent::Stmt(outer) + if outer.is_some() && matches!(hir[outer].kind, StmtKind::Try { .. })), + _ => true, + }; + if !is_host { + return None; + } return host( s.loc, s.start, @@ -1813,6 +2419,34 @@ impl Unused<'_, '_> { false, ); } + // `parseClassElement`: a `;` is a member of the class too, for which the HIR has nothing. + // Any other `;` in a class ends a member or a statement that starts in the class. + let text: &[u8] = &hir.text; + let next_token = bun_core::strings::index_of(&text[at as usize..], b"*/") + .map(|end| skip_trivia(text, at as usize + end + 2) as u32); + if let Some(semicolon) = next_token.filter(|&it| text.get(it as usize) == Some(&b';')) { + let loc = TextRange { + pos: skip_trivia_back(text, semicolon as usize) as u32, + end: semicolon + 1, + }; + let classes = hir.classes.iter().zip(bound.class_owner.iter()); + let innermost = classes + .enumerate() + .filter(|(_, (class, owner))| (class.start..owner.end(hir)).contains(&semicolon)) + .max_by_key(|(_, (class, _))| class.start); + if let Some((i, (class, _))) = innermost + && follows(loc, semicolon) + { + let ends_with_it = |start: u32, loc: TextRange| { + start > class.start && (loc.pos..loc.end).contains(&semicolon) + }; + if !hir.members.iter().any(|m| ends_with_it(m.start, m.loc)) + && !hir.stmts.iter().any(|s| ends_with_it(s.start, s.loc)) + { + return host(loc, semicolon, bound.class_scope[i], false); + } + } + } let mut enum_members = hir.enum_members.iter().enumerate(); if let Some((i, m)) = enum_members.find(|(_, m)| follows(m.loc, m.pos)) { let scope = bound.enum_scope.get(bound.enum_member_owner[i].idx()); @@ -1820,25 +2454,43 @@ impl Unused<'_, '_> { } let mut parameters = hir.params.iter().enumerate(); if let Some((i, p)) = parameters.find(|(_, p)| follows(p.loc, p.pos)) { - let function = bound.param_fn[i]; - let scope = if function.is_some() { - bound.fns[function.idx()].scope - } else { - ScopeId::NONE - }; - return host(p.loc, p.pos, scope, true); + // `parseSimpleArrowFunctionExpression`: the comments belong to the `ArrowFunction` + // alone, which `checkSourceElement` never visits. + let parameter = hir.node(ParamId(i as u32)); + let function = hir.parent(parameter); + if hir.kind(function) == Kind::ArrowFunction + && hir.is_parameter_without_parentheses(function, parameter) + { + return None; + } + return host( + p.loc, + p.pos, + self.scope_of_parameter(ParamId(i as u32)), + true, + ); } - // `parseFunctionOrConstructorType`. `node.Pos()` of a type is not stored. + // `parseFunctionOrConstructorType`, `parseTupleElementNameOrTupleElementType`: the first + // token, `node.End()`, a type that is checked if the node is, and the scope. `node.Pos()` + // is stored for neither. let function_types = (hir.types.iter().enumerate()).filter_map(|(i, t)| match t.kind { - TypeNodeKind::Fn(f) if t.pos > at => Some((i, t, f)), + TypeNodeKind::Fn(f) => Some((t.pos, t.end, i, bound.fns[f.idx()].scope)), _ => None, }); - if let Some((i, t, f)) = function_types.min_by_key(|it| it.1.pos) { - let pos = skip_trivia_back(&hir.text, t.pos as usize) as u32; + let named_tuple_members = (hir.tuple_elems.iter()) + .filter(|member| member.name.is_some() && member.written.is_some()) + .map(|member| { + let written = member.written.idx(); + (member.start, member.end, written, bound.type_scope[written]) + }); + let after = function_types + .chain(named_tuple_members) + .filter(|node| node.0 > at); + if let Some((start, end, ty, scope)) = after.min_by_key(|node| node.0) { + let pos = skip_trivia_back(&hir.text, start as usize) as u32; if pos <= at { - let is_checked = !bound.is_unchecked_type(i) && !self.is_never_checked(t.pos); - let loc = TextRange { pos, end: t.end }; - return host(loc, t.pos, bound.fns[f.idx()].scope, false).filter(|_| is_checked); + let is_checked = !bound.is_unchecked_type(ty); + return host(TextRange { pos, end }, start, scope, false).filter(|_| is_checked); } } let mut declarations = hir.var_decls.iter().enumerate(); @@ -1848,42 +2500,73 @@ impl Unused<'_, '_> { if s.is_none() || !matches!(hir[s].kind, StmtKind::Var(_)) { return None; } - let scope = match bound.stmt_scope[s.idx()] { - ScopeId::NONE => self.scope_of_statement(s), - scope => scope, - }; - host(d.loc, hir[d.pat].pos, scope, true) + host(d.loc, hir[d.pat].pos, bound.stmt_scope[s.idx()], true) } - /// The scope of the declaration that `s` is. For any other statement, the scope of the - /// innermost enclosing function or namespace. - fn scope_of_statement(&self, mut s: StmtId) -> ScopeId { + /// `Resolve` from a child of `s` that is not a statement: the scope that `s` creates, or else + /// the scope it is in. + fn scope_of_statement(&self, s: StmtId) -> ScopeId { let (hir, bound) = (self.hir, self.bound); - match hir[s].kind { + let inside = match hir[s].kind { StmtKind::Fn(f) => return bound.fns[f.idx()].scope, StmtKind::Class(class) => return bound.class_scope[class.idx()], StmtKind::Interface(id) => return bound.interface_scope[id.idx()], StmtKind::TypeAlias(alias) => return bound.alias_scope[alias.idx()], StmtKind::Enum(e) => return bound.enum_scope[e.idx()], StmtKind::Module(m) => return bound.module_scope[m.idx()], - _ => {} - } - loop { - match bound.stmt_parent[s.idx()] { - Parent::Stmt(outer) if outer.is_some() => s = outer, - Parent::Case(case) if bound.case_stmt[case.idx()].is_some() => { - s = bound.case_stmt[case.idx()] - } - Parent::FnBody(f) => return bound.fns[f.idx()].scope, - Parent::Module(m) => return bound.module_scope[m.idx()], - Parent::File => return ScopeId(0), - _ => return ScopeId::NONE, + StmtKind::For { body, .. } + | StmtKind::ForIn { body, .. } + | StmtKind::ForOf { body, .. } + if body.is_some() => + { + body } - } + // An empty block declares nothing. + StmtKind::Block(list) => hir.ids(list).next().unwrap_or(s), + _ => s, + }; + bound.stmt_scope[inside.idx()] + } + + /// `reparseJSDocComment`: in JavaScript the comment of a `@param`, `@property` or `@this` tag + /// that is nested in another tag is the JSDoc of each parameter and property signature made + /// from the tag. Where the names in the comment of the tag at `tag` are resolved from. + fn scopes_of_reparsed_tag(&self, tag: u32) -> Vec { + let hir = self.hir; + if !hir.is_js { + return Vec::new(); + } + let is_made_from_it = + |flags: Flags, loc: TextRange| flags.contains(Flags::REPARSED) && loc.pos == tag; + let members = (hir.members.iter().enumerate()) + .filter(|(_, m)| is_made_from_it(m.flags, m.loc)) + .map(|(i, _)| self.scope_of_member(MemberId(i as u32))); + let parameters = (hir.params.iter().enumerate()) + .filter(|(_, p)| is_made_from_it(p.flags, p.loc)) + .map(|(i, _)| self.scope_of_parameter(ParamId(i as u32))); + let scopes = members.chain(parameters); + scopes.filter(|scope| scope.is_some()).collect() + } + + /// `Resolve` from a child of `p`, so that `lastLocation` is a parameter where the locals of the + /// function are searched. + fn scope_of_parameter(&self, p: ParamId) -> ScopeId { + let bound = self.bound; + let function = bound.param_fn[p.idx()]; + if function.is_none() { + return ScopeId::NONE; + } + let scope = bound.fns[function.idx()].scope; + // The scopes inside a function follow its own. + let mut inside = (bound.scopes.iter().enumerate().skip(scope.idx() + 1)) + .take_while(|(_, inner)| inner.parent >= scope); + inside + .find(|(_, inner)| inner.kind == ScopeKind::Param(function)) + .map_or(scope, |(i, _)| ScopeId(i as u32)) } /// `GetHostSignatureFromJSDoc`: the scope of the signature that `m` is, or that is the type of - /// `m` if it is a property signature. Otherwise the scope `m` is declared in. + /// `m` if it is a property signature. Otherwise the scope that encloses `m`. fn scope_of_member(&self, m: MemberId) -> ScopeId { let (hir, bound) = (self.hir, self.bound); let (member, owner) = (&hir[m], bound.member_owner[m.idx()]); @@ -1902,19 +2585,15 @@ impl Unused<'_, '_> { { return bound.fns[f.idx()].scope; } - match owner { - MemberOwner::Class(class) => bound.class_scope[class.idx()], - MemberOwner::Interface(id) => bound.interface_scope[id.idx()], - MemberOwner::TypeLiteral(t) => bound.type_scope[t.idx()], - MemberOwner::None => ScopeId::NONE, - } + bound.member_scope[m.idx()] } - /// The lookups of the first of `names`, the `a.b` of `import x = a.b`. - fn note_module_reference(&mut self, scope: ScopeId, names: Span) { + /// The lookups of the first of `names`, the `a.b` of `import x = a.b`, that are made whether or + /// not `x` is referenced. Returns whether the target of `x` is `unknownSymbol`. + fn note_module_reference(&mut self, scope: ScopeId, names: Span) -> bool { let names: Vec = self.hir.texts(names).collect(); let Some(&first) = names.first() else { - return; + return false; }; let any = SymFlags::VALUE | SymFlags::TYPE | SymFlags::NAMESPACE; // `getSymbolOfPartOfRightHandSideOfImportEquals` @@ -1936,6 +2615,7 @@ impl Unused<'_, '_> { let meaning = SymFlags::VALUE | SymFlags::NAMESPACE; self.note_name(scope, first, meaning, VALUE | NAMESPACE); } + target.is_none() } /// `resolveEntityName(name, SymbolFlagsNamespace)`: a name that does not resolve to a namespace @@ -1967,6 +2647,20 @@ impl Unused<'_, '_> { /// `Resolve`: what the name resolves to, if that is declared in the file. fn resolve_use(&self, from: ScopeId, name: Atom, meaning: SymFlags) -> Option { + let files = self.files; + self.resolve_use_with(from, name, meaning, &mut |held, meaning| { + held.filter(|&sym| files.means(sym, meaning)) + }) + } + + /// The same. `get_symbol`: `getSymbol`, given the entry of a table for the name. + fn resolve_use_with( + &self, + from: ScopeId, + name: Atom, + meaning: SymFlags, + get_symbol: &mut dyn FnMut(Option, SymFlags) -> Option, + ) -> Option { let files = self.files; // The most recently searched scope. let mut found_in = ScopeId::NONE; @@ -1974,7 +2668,7 @@ impl Unused<'_, '_> { if let SymbolTable::Locals(_, scope) = table { found_in = scope; } - held.filter(|&sym| files.means(sym, meaning)) + get_symbol(held, meaning) }; let start = self.bound.scope_to_resolve_from(from, name); let found = files @@ -1990,10 +2684,18 @@ impl Unused<'_, '_> { let mut inside = SymbolId::NONE; let mut scope = from; while scope != found_in { + let s = &self.bound.scopes[scope.idx()]; + // The name of a method or an accessor is a child of it, but its scope is not inside + // that of the function. + if let ScopeKind::FunctionName(f) = s.kind + && self.bound.fns[f.idx()].scope == found_in + { + break; + } if self.owner_of_scope[scope.idx()].is_some() { inside = self.owner_of_scope[scope.idx()]; } - scope = self.bound.scopes[scope.idx()].parent; + scope = s.parent; } Some(Use { symbol: found, @@ -2036,11 +2738,9 @@ impl Unused<'_, '_> { } } - /// Whether the checker never visits `e`, so that nothing in `e` counts as a reference. `checkWithStatement` does not check the body - /// of a `with` statement. + /// Whether the checker never visits `e`, so that nothing in `e` counts as a reference. fn is_unchecked(&self, e: ExprId) -> bool { - self.hir.is_in_with(self.hir[e].pos) - || self.has_unchecked_returns && self.is_in_unchecked_return(e) + self.has_unchecked_returns && self.is_in_unchecked_return(e) || self.is_never_checked(self.hir[e].pos) } @@ -2049,6 +2749,24 @@ impl Unused<'_, '_> { never_checked.any(|&(from, to)| (from..to).contains(&pos)) } + /// Not `is_never_checked` for the node of `scope`, a `ScopeKind::Block`. The scope does not + /// store the node: it is `GetEnclosingBlockScopeContainer` of every declaration among its + /// locals (`bindBlockScopedDeclaration`). + fn is_block_scope_checked(&self, scope: ScopeId) -> bool { + if self.never_checked.is_empty() { + return true; + } + let (hir, bound) = (self.hir, self.bound); + let first = bound.table(bound.scopes[scope.idx()].locals).first(); + let Some(&declaration) = first.and_then(|it| bound.symbols[it.1.idx()].decls.first()) + else { + return true; + }; + let container = hir.get_enclosing_block_scope_container(hir.node(declaration)); + // A `CaseBlock` is a part of its statement. + container.is_none() || !self.is_never_checked(hir.start(container.row())) + } + /// Whether `e` is in the expression of a `return` that is outside a function or directly in a class static block. /// `checkReturnStatement` reports such a statement and returns before it checks the expression. fn is_in_unchecked_return(&self, e: ExprId) -> bool { @@ -2303,7 +3021,8 @@ impl Unused<'_, '_> { impl Checker<'_, '_> { /// `checkUnusedIdentifiers`. The nodes `registerForUnusedIdentifiersCheck` collects there are - /// iterated by kind here. + /// iterated by kind here. The check of a node collects it, so one that is never checked is not + /// among them, wherever the declarations of its locals are. fn check_unused_identifiers(&mut self, u: &Unused<'_, '_>) { let (hir, bound) = (u.hir, u.bound); let unchecked = self.unchecked_jsdoc_types(u.file); @@ -2312,12 +3031,15 @@ impl Checker<'_, '_> { // `checkSourceFile`: `IsExternalOrCommonJSModule` ScopeKind::File => hir.has_module_syntax || bound.commonjs_indicator.is_some(), // `checkModuleDeclaration`: `!IsGlobalScopeAugmentation(node)` - ScopeKind::Module(m) => hir[m].name != ModuleName::Global, - ScopeKind::Block => true, + ScopeKind::Module(m) => { + hir[m].name != ModuleName::Global && !u.is_never_checked(hir[m].name_pos) + } + ScopeKind::Block => u.is_block_scope_checked(ScopeId(i as u32)), // Among overloads, only the implementation. ScopeKind::Fn(f) => { !matches!(hir[f].body, FnBody::None) && hir.kind(hir.node(f)).is_function_like_declaration() + && !u.is_never_checked(hir[f].start) } _ => false, }; @@ -2357,6 +3079,7 @@ impl Checker<'_, '_> { if let TypeNodeKind::Infer(param) = t.kind && hir[param].name != known::empty && !unchecked.contain(t.pos) + && !u.is_never_checked(t.pos) && u.is_unreferenced_type_parameter(param) { let at = self.place_of_token(u.file, hir[param].pos); @@ -2382,7 +3105,7 @@ impl Checker<'_, '_> { ) { let is_error = if is_parameter { u.parameters } else { u.locals }; if is_error && !u.hir.is_ambient(location) && !u.has_syntax_error(location) { - self.error_at(at, code, args); + self.error_at(at, code, args).by_another_node = true; } } @@ -2425,7 +3148,11 @@ impl Checker<'_, '_> { .push((hir.find_ancestor(declaration, is_clause), declaration)); } } - // `export default function f() {}`. `IsAmbientModule` + // `IsAmbientModule` + Kind::ModuleDeclaration + if matches!(decl, Decl::Module(m) + if !matches!(hir[m].name, ModuleName::Ident(_))) => {} + // `export default function f() {}` Kind::FunctionDeclaration | Kind::ClassDeclaration | Kind::InterfaceDeclaration @@ -2434,6 +3161,7 @@ impl Checker<'_, '_> { | Kind::EnumDeclaration | Kind::ModuleDeclaration | Kind::ImportEqualsDeclaration + | Kind::ExportSpecifier if !hir .flags(declaration) .intersects(Flags::EXPORT | Flags::DEFAULT) @@ -2521,6 +3249,9 @@ impl Checker<'_, '_> { matches!(hir.data(hir.find_ancestor(node, is_statement)), NodeData::Stmt(s) if matches!(hir[s].kind, StmtKind::Import(i) if hir[i].type_only)) } + Kind::ExportSpecifier => { + matches!(hir.data(node), NodeData::ExportSpec(s) if hir[hir[s].export].type_only) + } _ => false, }; let at = self.place_of_token(u.file, hir.start(hir.name(node))); @@ -2578,6 +3309,9 @@ impl Checker<'_, '_> { return; } let node = hir.node(declaration); + if u.is_never_checked(hir.start(node)) { + return; + } if params.len() > 1 && params.iter().all(|p| u.is_unreferenced_type_parameter(p)) { // `rangeOfTypeParameters`: starts at the `<`. A list synthesized from `@template` tags // begins at the `@` of the first tag (`gatherTypeParameters`), so the range starts one @@ -2614,6 +3348,9 @@ impl Checker<'_, '_> { let MemberOwner::Class(_) = bound.member_owner[i] else { continue; }; + if u.is_never_checked(member.start) { + continue; + } match member.kind { MemberKind::Property | MemberKind::Method diff --git a/src/sema/check/explain_relation.rs b/src/sema/check/explain_relation.rs index 62d7a6f32691..3b993b671f93 100644 --- a/src/sema/check/explain_relation.rs +++ b/src/sema/check/explain_relation.rs @@ -733,6 +733,11 @@ impl<'p, 's> Checker<'p, 's> { if let Some(known) = self.p.equivalent_base_types.get(&self.task, &ty) { return known; } + // `ObjectFlagsIdenticalBaseTypeCalculated` is set before the base types are requested, so a recursive query gets nil. + let mut in_progress = self.identical_base_types_in_progress.iter(); + if in_progress.any(|it| it.0 == ty) { + return None; + } let (mut has_heritage_clause, mut extends_entity_name, mut has_members) = (false, true, false); for &(file, decl) in self.files().decls_of(target).iter() { @@ -770,7 +775,19 @@ impl<'p, 's> Checker<'p, 's> { { (None, true) } else { - let bases = self.base_types(target); + self.identical_base_types_in_progress + .push((ty, self.stack.len())); + let was_resolving = self.is_resolving(Query::Bases(target)); + // With one checker they are resolved by now, and this is that resolution over again. Whether it began here, with the flag + // set, only the task of the declaring file knows, which reports 2310 if not. `checkClassLikeDeclaration` begins here: it + // checks the type arguments of the heritage clause first. So this is taken for a recursive query. + let is_repeated = was_resolving && self.are_base_types_resolved_by_check(target); + let bases = if is_repeated { + List::default() + } else { + self.base_types(target) + }; + let found_cycle = was_resolving && !is_repeated && self.found_cycle; let base = match bases[..] { [mut base] if !has_members => { let args = self.type_arguments(ty); @@ -788,10 +805,12 @@ impl<'p, 's> Checker<'p, 's> { } _ => None, }; - // `base_types` returns an empty list while that query is in progress on this checker, so `base` can be provisional. It is - // final only if it was computed from the cached base types. + self.identical_base_types_in_progress.pop(); + // Where `pushTypeResolution` fails, `getBaseTypes` returns `resolvedBaseTypes` as it is, and what follows from that stays. + // Otherwise `base` is final only if it was computed from the cached base types. let cached = self.p.base_types.get_ref(&self.task, &target); - let is_final = has_members || cached.map(|it| &it[..]) == Some(&bases[..]); + let is_final = + has_members || found_cycle || cached.map(|it| &it[..]) == Some(&bases[..]); (base, is_final) }; match self.end_scope_as(scope, !is_final) { @@ -831,11 +850,11 @@ impl<'p, 's> Checker<'p, 's> { } else if self.is_reference_to_global(source, known::Object, 0) { self.report_error(r, 2696, &[]); } else if is_jsx && self.is_intersection(target) { + let (file, location) = (r.error_node.0, self.jsx_element_around(r.error_node)); if let TypeData::Intersection(parts) = self.data(target) - && let Some(file) = self.task.file && let (Some(a), Some(b)) = ( - self.jsx_type(file, Node::FILE, known::IntrinsicAttributes), - self.jsx_type(file, Node::FILE, known::IntrinsicClassAttributes), + self.jsx_type(file, location, known::IntrinsicAttributes), + self.jsx_type(file, location, known::IntrinsicClassAttributes), ) && (parts.contains(&a) || parts.contains(&b)) { @@ -859,6 +878,22 @@ impl<'p, 's> Checker<'p, 's> { } } + /// `error_node` as the location that `getJsxNamespaceAt` resolves a name from: the opening of + /// the innermost JSX element around it. `Node::FILE`: there is none. + fn jsx_element_around(&mut self, error_node: Place) -> Node { + let (file, start, end) = error_node; + if end == 0 { + return Node::FILE; + } + let (hir, by_kind) = (self.hir(file), self.exprs_by_kind(file)); + let elements = by_kind.of(ExprTag::Jsx).iter().copied(); + let around = elements.filter(|&e| hir[e].pos <= start && start < hir[e].end); + match around.max_by_key(|&e| hir[e].pos) { + Some(element) => self.jsx_opening_like(file, element), + None => Node::FILE, + } + } + /// `hasNonCircularBaseConstraint` of the `syntheticParam` of `reportErrorResults`: a clone of /// the type parameter `source`, declared as `declared`, whose constraint is `target` with /// `source` replaced by the clone. diff --git a/src/sema/check/expr.rs b/src/sema/check/expr.rs index a05e8c6e1824..1712ab4bb331 100644 --- a/src/sema/check/expr.rs +++ b/src/sema/check/expr.rs @@ -20,6 +20,18 @@ enum PatternKind { Assignment, } +/// What `checkObjectLiteral` finds out about the literal before its member loop. +#[derive(Copy, Clone)] +struct ObjectLiteralContext { + /// `inDestructuringPattern` + in_destructuring_pattern: bool, + /// `contextualType`, if `contextualTypeHasPattern` and the pattern has no + /// `ObjectFlagsObjectLiteralPatternWithComputedProperties`. + implied: Option, + /// `inConstContext` + in_const_context: bool, +} + /// `getAssignmentTargetKind` #[derive(Copy, Clone)] pub(super) struct TargetKind { @@ -44,12 +56,13 @@ pub(super) struct LeftOfPropertyAccess { } impl<'p, 's> Checker<'p, 's> { - /// `getQuickTypeOfExpression`. Not for a literal, whose type `checkExpression` has as quickly. + /// `getQuickTypeOfExpression` pub(super) fn quick_type_of_expr(&mut self, file: FileId, e: ExprId) -> Option { if e.is_none() { return None; } - match self.hir(file)[e].kind { + let hir = self.hir(file); + match hir[e].kind { ExprKind::Await(x) => { let ty = self.quick_type_of_expr(file, x)?; Some(self.awaited(ty)) @@ -58,6 +71,20 @@ impl<'p, 's> Checker<'p, 's> { ExprKind::Call(_) => self.quick_type_of_call(file, e), // The operand is not checked. `x as const` is `ExprKind::AsConst`. ExprKind::As { ty, .. } => Some(self.type_from_node(file, ty)), + // `IsLiteralExpression(node) || IsBooleanLiteral(node)`: `node` is a `ParenthesizedExpression` if there is one. + ExprKind::Number(_) + | ExprKind::BigInt(_) + | ExprKind::String(_) + | ExprKind::Regex + | ExprKind::True + | ExprKind::False + if !is_parenthesized(hir, e) => + { + Some(self.type_of_expr(file, e)) + } + ExprKind::Template { exprs } if exprs.is_empty() && !is_parenthesized(hir, e) => { + Some(self.type_of_expr(file, e)) + } _ => None, } } @@ -182,20 +209,7 @@ impl<'p, 's> Checker<'p, 's> { }; if c.adopt_generic_argument(n, instantiated, contextual_signature) { n.inferred_type_params.extend(unique); - // `getSignatureInstantiationWithoutFillingInTypeArguments` - let (params, ret, this) = ( - c.sig_params(instantiated), - c.sig_return(instantiated), - c.sig_this_type(instantiated), - ); - return c.types().intern_sig(SigData::Synth { - type_params: ArenaBox::empty(), - params: c.list(¶ms), - ret, - this, - of: ArenaBox::empty(), - is_union: true, - }); + return c.without_filling_in_type_arguments(instantiated); } } // `instantiateSignatureInContextOf`. `applyToParameterTypes` reads as many parameters @@ -260,13 +274,14 @@ impl<'p, 's> Checker<'p, 's> { if e.is_none() { return TypeId::UNRESOLVED; } - if self.contextual_binding_patterns.is_empty() - && !self.is_rechecked(file, e) + let is_rechecked = self.is_rechecked(file, e); + if !is_rechecked + && self.contextual_binding_patterns.is_empty() && let Some(known) = self.cached_type_of_expr(file, e) { return known; } - self.type_of_expr_on_cache_miss(file, e) + self.type_of_expr_on_cache_miss(file, e, is_rechecked) } /// Whether `e` is rechecked without caching. tsgo rechecks everything in an argument for every @@ -275,6 +290,8 @@ impl<'p, 's> Checker<'p, 's> { /// have the same type under every contextual type, and are checked once, unless a type /// parameter is in scope: `getNarrowableTypeForReference` substitutes the constraint for a type /// parameter or not, depending on the check mode and on `hasContextualTypeWithNoGenericTypes`. + /// It does the same for `this["p"]` and `keyof this`, and a `this` type is in scope in every + /// method: there the one check finds out, see `is_reference_to_recheck`. #[inline] fn is_rechecked(&mut self, file: FileId, e: ExprId) -> bool { self.is_rechecking() @@ -312,14 +329,28 @@ impl<'p, 's> Checker<'p, 's> { false } + /// Whether the innermost frame `may_substitute_constraints`. It is the frame of a reference + /// that is checked once, in `CheckModeNormal`, while its parent is rechecked. What it has + /// reported is dropped, nothing of it is stored, and the caller rechecks the reference. + fn is_reference_to_recheck(&mut self) -> bool { + let Some(frame) = self.frames.last_mut() else { + return false; + }; + frame.drops_reported |= frame.may_substitute_constraints; + frame.may_substitute_constraints + } + /// The same for an `e` that exists and whose type is not cached, or may be rechecked. - fn type_of_expr_on_cache_miss(&mut self, file: FileId, e: ExprId) -> TypeId { + fn type_of_expr_on_cache_miss( + &mut self, + file: FileId, + e: ExprId, + is_rechecked: bool, + ) -> TypeId { + let is_checked_once = !is_rechecked && self.is_rechecking(); // `getTypeFromBindingElement`: the defaults in a pattern are rechecked every time the type // the pattern implies for its initializer is computed. The names of the pattern are typed - // as any in the meantime. - let is_rechecked = self.is_rechecked(file, e); - // While the implied type of a pattern is being computed its names are typed as any, so the - // result is not valid for other callers. + // as any in the meantime, so the result is not valid for other callers. let is_memoised = is_rechecked && self.contextual_binding_patterns.is_empty(); if is_memoised && let Some(&known) = self.rechecked_exprs.get(&(file, e)) { return known; @@ -362,11 +393,20 @@ impl<'p, 's> Checker<'p, 's> { { return ty; } - if matches!( - self.hir(file)[e].kind, - ExprKind::Binary { .. } | ExprKind::Call(_) - ) { - self.resolve_chain_from_the_inside(file, e); + let hir = self.hir(file); + match hir[e].kind { + ExprKind::Binary { .. } | ExprKind::Call(_) => { + self.resolve_chain_from_the_inside(file, e); + } + // `checkNonNullExpression(expr)`: the object is checked in `CheckModeNormal`. + ExprKind::Dot { obj, .. } + if !is_rechecked && matches!(hir[obj].kind, ExprKind::Dot { .. }) => + { + let outer = self.suspend_recheck(); + self.resolve_chain_from_the_inside(file, e); + self.end_recheck(outer); + } + _ => {} } let (ty, stored) = match self.type_of_plain_literal(file, e) { Some(ty) => (ty, Some(Stored::new())), @@ -383,6 +423,10 @@ impl<'p, 's> Checker<'p, 's> { return TypeId::UNRESOLVED; } let ty = self.type_of_entered_expr(file, e, is_rechecked); + if is_checked_once && self.is_reference_to_recheck() { + let _ = self.leave(Query::Expr(file, e)); + return self.type_of_expr_on_cache_miss(file, e, true); + } if afresh && self.inference_contexts.len() != self.context_free_level && !(self.frames.last()).is_some_and(|it| it.is_stored_by_nested_visit) @@ -405,6 +449,13 @@ impl<'p, 's> Checker<'p, 's> { { self.cache_type_of_expr(file, e, ty, stored); self.note_stored_by_nested_visit(Query::Expr(file, e)); + if self.serialization_level >= super::sink::MAX_SERIALIZATION_LEVEL { + self.note_cached_discarding(file, e); + } else if !self.expressions_cached_discarding.is_empty() && self.task.file == Some(file) + { + // A check around the one that was the first to assign has reported. + self.expressions_cached_discarding.retain(|&it| it != e); + } } if stored.is_some() && is_memoised { self.rechecked_exprs.insert((file, e), ty); @@ -412,6 +463,15 @@ impl<'p, 's> Checker<'p, 's> { ty } + /// `links.resolvedType` of `e` is assigned at `maxSerializationLevel`. See + /// `expressions_cached_discarding`. + #[cold] + fn note_cached_discarding(&mut self, file: FileId, e: ExprId) { + if self.task.file == Some(file) && self.is_checked_by_check_expression_cached(file, e) { + self.expressions_cached_discarding.push(e); + } + } + /// The type of `e` if it is a literal that needs no query, so that no cycle can re-enter it and /// no result can turn out provisional in the meantime. It leaves the same state as `enter` and /// `leave` would. `None` also where `enter` would fail. @@ -506,6 +566,7 @@ impl<'p, 's> Checker<'p, 's> { .iter() .rposition(|&q| q == Query::Expr(file, e))?; let pushed_at = self.flow_loop_pushed_since(first)?; + let is_checked_once = !is_rechecked && self.is_rechecking(); // Hides the first visit from `enter`, which still fails when time, native stack or query // depth run out. let resolution_start = std::mem::replace(&mut self.resolution_start, self.stack.len()); @@ -518,7 +579,11 @@ impl<'p, 's> Checker<'p, 's> { // The loop type is incomplete: nothing computed since the loop was pushed is cached. self.taint_from(pushed_at); let ty = self.type_of_entered_expr(file, e, is_rechecked); + let is_checked_again = is_checked_once && self.is_reference_to_recheck(); let _ = self.leave(Query::Expr(file, e)); + if is_checked_again { + return self.recheck_in_flow_loop(file, e, true); + } Some(ty) } @@ -557,41 +622,48 @@ impl<'p, 's> Checker<'p, 's> { self.type_of_expr(file, e); } - /// `a.b().c().d()` with hundreds of links, `a + b + c + ..` with hundreds of operands: resolved - /// one by one from the innermost, so that no resolution recurses all the way down. + /// `a.b().c().d()` with hundreds of links, `a + b + c + ..` with hundreds of operands, `A.B.C. + /// ..` with hundreds of names: resolved one by one from the innermost, so that no resolution + /// recurses all the way down. fn resolve_chain_from_the_inside(&mut self, file: FileId, e: ExprId) { let hir = self.hir(file); let mut chain: Vec = Vec::new(); match hir[e].kind { - // `checkBinaryLikeExpression` descends the left operands to any depth. - ExprKind::Binary { left, .. } => { - // The left operand of `at`, if `at` is a binary expression whose type is not cached - // yet. - let further = |c: &mut Self, at: ExprId| { + // `checkBinaryLikeExpression` descends the left operands to any depth, and + // `checkPropertyAccessExpression` the objects. + ExprKind::Binary { left: first, .. } | ExprKind::Dot { obj: first, .. } => { + let tag = hir[e].kind.tag(); + // The left operand or the object of `at`, if `at` is of the kind of `e`. + let further = |at: ExprId| { if at.is_none() { return None; } match hir[at].kind { - ExprKind::Binary { left, .. } if !c.has_type_of_expr(file, at) => { - Some(left) + ExprKind::Binary { left: next, .. } | ExprKind::Dot { obj: next, .. } => { + (hir[at].kind.tag() == tag).then_some(next) } _ => None, } }; - let (mut at, mut len) = (left, 0usize); - while let Some(next) = further(self, at) { - len += 1; + // FOR SPEED: a short chain reads no table. + let mut at = first; + for _ in 0..16 { + let Some(next) = further(at) else { + return; + }; at = next; } - if len < 16 { - return; - } - chain.reserve_exact(len); - at = left; - while let Some(next) = further(self, at) { + // Up to one whose type is cached. + at = first; + while let Some(next) = further(at) + && !self.has_type_of_expr(file, at) + { chain.push(at); at = next; } + if chain.len() < 16 { + return; + } } ExprKind::Call(_) => { // The receiver of `at`, and whether `at` is a call before `e`. `None` at the start @@ -906,6 +978,21 @@ impl<'p, 's> Checker<'p, 's> { && self.base_constraint(ty) == TypeId::UNKNOWN } + /// `GetErrorRangeForNode(right)` for the name of a property access: a missing identifier is + /// empty. + pub(super) fn place_of_right( + &self, + file: FileId, + name: Atom, + name_pos: u32, + ) -> (FileId, u32, u32) { + if name == known::empty { + (file, name_pos, name_pos) + } else { + self.place_of_token(file, name_pos) + } + } + /// `checkPropertyAccessExpressionOrQualifiedName`: the type of `a.b` when it is reached, and /// whether the chain may short-circuit before it. fn type_of_property_access(&mut self, file: FileId, e: ExprId) -> (TypeId, bool) { @@ -928,6 +1015,7 @@ impl<'p, 's> Checker<'p, 's> { return (access.any_like.unwrap_or(TypeId::ERROR), stops); } let lexical = if is_private { + self.note_external_emit_helpers_check(file, e); self.lookup_symbol_for_private_identifier_declaration(file, e, name) } else { None @@ -1015,6 +1103,17 @@ impl<'p, 's> Checker<'p, 's> { { return (TypeId::UNRESOLVED, stops); } + // One checker has checked `file` by now, and the access with it, before those base types + // were requested. Nothing is stored, so the task of `file` evaluates it, and reports. + if let TypeData::Ref { target, .. } = *self.data(apparent) + && let Some(height) = self.stack.iter().position(|&q| q == Query::Bases(target)) + && self.task.checker_count == 0 + && !self.is_emitting + && !self.is_reported_in_time_under_resolution(height, file) + { + self.mark_tainted_from(self.frames.len().saturating_sub(1)); + return (TypeId::ERROR, stops); + } if is_private { // `#x in o` is narrowed like `"#x" in o`, not to the class: that produces a `#x` // that no class declares, and the correct type of `o` is not known. @@ -1048,7 +1147,7 @@ impl<'p, 's> Checker<'p, 's> { .. } ) { - let right = self.place_of_token(file, name_pos); + let right = self.place_of_right(file, name, name_pos); if self.is_block_scoped_global(name) { self.error_at(right, 2339, &[Arg::Atom(name), Arg::Type(left)]); } else if self.p.files.options.no_implicit_any { @@ -1101,19 +1200,14 @@ impl<'p, 's> Checker<'p, 's> { if self.p.files.options.no_property_access_from_index_signature && !bound.is_in_type_query(e) { - let right = self.place_of_token(file, name_pos); + let right = self.place_of_right(file, name, name_pos); self.error_at(right, 4111, &[Arg::Atom(name)]); } } else { - if let Some((class, declaration)) = lexical + // `isSetonlyAccessor` + if is_private && !target.definite - && hir[declaration].kind == MemberKind::Setter - && !hir[class].members.iter().any(|m| { - hir[m].kind == MemberKind::Getter - && hir[m].key == hir[declaration].key - && hir[m].flags.contains(Flags::STATIC) - == hir[declaration].flags.contains(Flags::STATIC) - }) + && prop.is_some_and(|prop| prop.flags.contains(PropFlags::WRITE_ONLY)) { let start = self.start_inside_parentheses(file, e); let node = (file, start, self.end_inside_parentheses(file, e)); @@ -1136,7 +1230,7 @@ impl<'p, 's> Checker<'p, 's> { && let Some(prop) = prop && self.is_assignment_to_readonly_entity(file, e, obj, prop) { - let right = self.place_of_token(file, name_pos); + let right = self.place_of_right(file, name, name_pos); let text = self.source_text(file, right.1, right.2); self.error_at(right, 2540, &[Arg::Bytes(&text)]); return (TypeId::ERROR, stops); @@ -1202,8 +1296,38 @@ impl<'p, 's> Checker<'p, 's> { } } - /// `isThisPropertyAccessInConstructor` for a property that only `this.name = value` assignments in a JavaScript class declare - /// (`isConstructorDeclaredThisProperty`). `e` is an access to the property `name` of `receiver`. Returns the initial type of + /// `isAutoTypedProperty` + fn is_auto_typed_property(&mut self, sym: Sym) -> bool { + let Some((file, Decl::Member(member))) = self.value_declaration_of_property(sym) else { + return false; + }; + let hir = self.hir(file); + hir.kind(hir.node(member)) == Kind::PropertyDeclaration + && hir[member].ty.is_none() + && hir[member].init.is_none() + && self.p.files.options.no_implicit_any + } + + /// `getDeclaringConstructor` for the symbol of `file` whose `Declarations` are `declarations`. + pub(super) fn get_declaring_constructor( + &self, + file: FileId, + declarations: &[(FileId, Decl)], + ) -> Option { + let hir = self.hir(file); + declarations.iter().find_map(|&(of, declaration)| { + let node = match declaration { + Decl::ThisProperty(e) if of == file => hir.node(e), + Decl::Member(member) if of == file => hir.node(member), + _ => return None, + }; + let container = hir.get_this_container(node, false, false); + (hir.kind(container) == Kind::Constructor).then(|| hir.function_of(container)) + }) + } + + /// `isThisPropertyAccessInConstructor`. Only in a JavaScript file is a `this.name = value` a declaration, so that + /// `getDeclaringConstructor` finds one. `e` is an access to the property `name` of `receiver`. Returns the initial type of /// `getFlowTypeOfProperty` if `e` is directly in the constructor that declares the property. pub(super) fn auto_this_property( &mut self, @@ -1226,17 +1350,34 @@ impl<'p, 's> Checker<'p, 's> { let PropSource::Symbol(sym) = prop.source else { return None; }; + if sym.file != file { + return None; + } let declarations = self.declarations_of_property(sym); - if sym.file != file - || !self.is_declared_by_assignment(sym) - || !matches!( - self.is_constructor_declared_this_property(file, &declarations), - super::shape::ThisAssignmentDeclaration::Constructor(declaring) if declaring == container - ) - { + let is_auto_typed = self.is_auto_typed_property(sym); + let constructor = if self.is_declared_by_assignment(sym) { + match self.is_constructor_declared_this_property(file, &declarations) { + super::shape::ThisAssignmentDeclaration::Constructor(declaring) => Some(declaring), + _ => None, + } + } else if is_auto_typed && hir.is_this_property(hir.node(e)) { + self.get_declaring_constructor(file, &declarations) + } else { + None + }; + if constructor != Some(container) { return None; } // `getFlowTypeOfProperty` + let has_declare_modifier = matches!( + self.value_declaration_of_property(sym), + Some((of, Decl::Member(member))) + if (self.hir(of).find_modifier(self.hir(of)[member].modifiers, Flags::AMBIENT)) + .is_some() + ); + if is_auto_typed && !has_declare_modifier { + return Some(TypeId::UNDEFINED); + } let (class, _) = self.class_of_member_fn(file, container)?; let inherited = self.type_of_property_in_base_class(file, class, name); Some(inherited.unwrap_or(TypeId::UNDEFINED)) @@ -1252,14 +1393,8 @@ impl<'p, 's> Checker<'p, 's> { receiver: TypeId, name: Atom, ) -> bool { - if !self.bound(file).private_class.contains_key(&e) { - return false; - } - let apparent = self.apparent_type(receiver); - self.parts(apparent).iter().all(|&part| { - let part = self.apparent_type(part); - self.prop_ref(part, name).is_some() - }) + self.bound(file).private_class.contains_key(&e) + && self.get_property_of_type(receiver, name).is_some() } /// An export of the module whose type is `ty` that resolves to a value, although it is exported @@ -1412,10 +1547,6 @@ impl<'p, 's> Checker<'p, 's> { } None => None, }; - // `getPropertyTypeForIndexType` has narrowed the type of whatever it found, of a method - // too, which `getFlowTypeOfAccessExpression` then leaves as it is. - let prop = - prop.filter(|prop| target.definite || self.is_variable_property_or_accessor(prop)); let index_expression = ( file, self.start_of(file, index), @@ -1676,6 +1807,12 @@ impl<'p, 's> Checker<'p, 's> { ExprKind::Cond { test, yes, no } => { let tested = self.type_of_expr(file, test); self.check_truthiness_of_type(file, test, tested); + self.look_at_with(|c| { + let body = Parent::Expr(yes); + c.check_testing_known_truthy_callable_or_awaitable_or_enum_member_type( + file, test, body, + ); + }); let (yes, no) = (self.type_of_expr(file, yes), self.type_of_expr(file, no)); self.union_reduced(&[yes, no]) } @@ -1707,25 +1844,12 @@ impl<'p, 's> Checker<'p, 's> { self.check_awaited_type(ty, true, self.place_of_expr(file, e), 1320) } ExprKind::Yield { value, star } => self.type_of_yield(file, e, value, star), + // `checkAssertion`. The callers of `getQuickTypeOfExpression` ask `quick_type_of_expr` + // first. ExprKind::As { expr, ty } => { - // `checkAssertion` checks the operand first. `getQuickTypeOfExpression`: not where - // the assertion is the whole initializer or the whole assigned value, whose type - // control flow analysis requests. - let is_quick = match self.bound(file).expr_parent[e.idx()] { - Parent::VarInit(_) - | Parent::ParamDefault(_) - | Parent::MemberInit(_) - | Parent::PatPropDefault(_) - | Parent::PatElemDefault(_) => true, - Parent::Expr(p) => { - matches!(hir[p].kind, ExprKind::Assign { op: None | Some(BinOp::And | BinOp::Or | BinOp::Nullish), value, .. } if value == e) - } - _ => false, - }; - if !is_quick { - self.look_at(file, expr); - self.look_at_type_node(file, ty); - } + self.look_at(file, expr); + self.look_at_type_node(file, ty); + self.check_node_deferred(file, e); self.type_from_node(file, ty) } // `checkNonNullAssertion` @@ -1905,7 +2029,7 @@ impl<'p, 's> Checker<'p, 's> { /// `isCommonJSRequire`: `require("m")` in JavaScript, where `require` is not defined by the /// program itself. - pub(super) fn is_commonjs_require(&self, file: FileId, e: ExprId) -> bool { + pub(super) fn is_commonjs_require(&mut self, file: FileId, e: ExprId) -> bool { let hir = self.hir(file); if !hir.is_js || crate::bind::required_specifier(hir, e).is_none() { return false; @@ -1942,14 +2066,14 @@ impl<'p, 's> Checker<'p, 's> { is_first_ambient == Some(true) } - /// `getResolvedSymbol`: the symbol an identifier resolves to as a value. - pub fn symbol_of_identifier(&self, file: FileId, e: ExprId, name: Atom) -> Option { - self.resolve_identifier(file, e, name, false) - .unwrap_or(None) + /// `getResolvedSymbol`: the symbol an identifier resolves to as a value. `None`: `unknownSymbol` or `argumentsSymbol`. + pub fn symbol_of_identifier(&mut self, file: FileId, e: ExprId, name: Atom) -> Option { + let found = self.resolve_identifier(file, e, name, false).ok()??; + self.value_symbol_of_identifier(file, e, name, found) } - /// `resolveEntityName` with `SymbolFlagsValue`, for an identifier that is an expression. `Err`: - /// the error code `Files::resolve` returns. + /// What the symbol tables have for `resolveName` with `SymbolFlagsValue`, for an identifier that is an expression: see + /// `value_symbol_of_identifier`. `Err`: the error code `Files::resolve` returns. pub fn resolve_identifier( &self, file: FileId, @@ -2073,11 +2197,12 @@ impl<'p, 's> Checker<'p, 's> { let declared = self.type_of_symbol(sym); // `getTypeOfVariableOrParameterOrProperty` returns the type it computed to the first caller and `links.resolvedType` to every // later caller. The two differ after a circularity that goes through a call. A reference in the variable's own initializer - // is never the first caller: the declaration is. + // is never the first caller: the declaration is. While that call is in progress, the reference is the caller of a nested one. let declared = if self.cycles != cycles_before && let Some(cached) = self.p.symbol_types.get(&self.task, &sym) && cached != declared && self.is_in_own_initializer(file, e, sym) + && !self.is_type_of_variable_in_progress(sym) { cached } else { @@ -2152,6 +2277,19 @@ impl<'p, 's> Checker<'p, 's> { .is_some() } + /// Whether a call of `getTypeOfVariableOrParameterOrPropertyWorker` for the variable `sym` is + /// in progress. `Query::Symbol` and `Query::Pat` are one resolution in tsgo. + fn is_type_of_variable_in_progress(&self, sym: Sym) -> bool { + self.stack.iter().any(|&q| match q { + Query::Symbol(symbol) => symbol == sym, + Query::Pat(file, name) => { + let symbol = self.bound(file).pat_symbol[name.idx()]; + symbol.is_some() && self.files().sym(file, symbol) == sym + } + _ => false, + }) + } + /// Whether `e` is assigned and not read: the left side of `=`, or part of a pattern there. #[inline] pub fn is_definite_assignment_target(&self, file: FileId, e: ExprId) -> bool { @@ -2338,7 +2476,7 @@ impl<'p, 's> Checker<'p, 's> { } // `getFlowTypeOfReference(node, thisType)` if container != Node::FILE { - self.narrow_this(file, e, t) + self.flow_type_of_reference(file, e, t) } else { t } @@ -2375,21 +2513,12 @@ impl<'p, 's> Checker<'p, 's> { if full_signature.is_none() && f.this_param.is_some() { return Some(self.type_of_this_parameter(file, func)); } - // `getSignatureFromDeclaration`: if only one accessor of a pair declares the type - // of `this`, it applies to both. - let expected = match f.kind { - FnKind::Getter => Some(FnKind::Setter), - FnKind::Setter => Some(FnKind::Getter), - _ => None, - }; - if let Some(expected) = expected - && let Some((of, other)) = self.sibling_accessor(file, func, expected) - { - let other = &self.hir(of)[other]; - if other.accessor_this_parameter().is_some() - && other.this_ty(self.hir(of)).is_some() - { - return Some(self.type_from_node(of, other.this_ty(self.hir(of)))); + // FOR SPEED: of the functions that declare no `this` parameter only an accessor has one in the signature of + // `getSignatureFromDeclaration`, that of the other accessor. + if matches!(f.kind, FnKind::Getter | FnKind::Setter) { + let sig = self.sig_of_fn(file, func); + if let Some(this) = self.sig_this_type(sig) { + return Some(this); } } if let FnOwner::Expr(owner) = self.bound(file).fns[func.idx()].owner @@ -2433,7 +2562,8 @@ impl<'p, 's> Checker<'p, 's> { } // "For a parameter of a set accessor, use the type of the get accessor if one is present" if f.kind == FnKind::Setter - && let Some((of, getter)) = self.sibling_accessor(file, func, FnKind::Getter) + && let Some((of, getter)) = + self.sibling_accessor_at_this_moment(file, func, FnKind::Getter) { if f.accessor_this_parameter().is_none() { let ty = self.return_type_of_fn(of, getter); @@ -2485,6 +2615,9 @@ impl<'p, 's> Checker<'p, 's> { if let Some(known) = self.p.type_node_types.get(&self.task, &(file, declared)) { return known; } + if let Some(raw) = self.provisional(Query::Pat(file, pat)) { + return TypeId(raw as u32); + } let error = TypeId::ERROR; if !self.enter(Query::Pat(file, pat)) { if !self.found_cycle { @@ -2496,8 +2629,11 @@ impl<'p, 's> Checker<'p, 's> { return error; } let ty = self.type_from_node(file, declared); - let _ = self.leave(Query::Pat(file, pat)); + let left = self.leave(Query::Pat(file, pat)); if !self.left_a_cycle { + if let Err(open) = left { + self.cache_provisionally(Query::Pat(file, pat), u64::from(ty.0), open); + } return ty; } if !self.is_parameter_of_context_sensitive_signature(file, p) { @@ -2643,7 +2779,7 @@ impl<'p, 's> Checker<'p, 's> { // literal. let this = match context { Some(context) => self.non_nullable(context), - None => self.type_of_expr(file, containing), + None => self.check_containing_object_literal_cached(file, containing, func), }; return Some(self.widened(this)); } @@ -2673,6 +2809,132 @@ impl<'p, 's> Checker<'p, 's> { None } + /// `checkExpressionCached(containingLiteral)` in `getContextualThisParameterType(func)`. It has no re-entrancy guard, and of + /// nested calls the outermost one assigns `links.resolvedType` last. + fn check_containing_object_literal_cached( + &mut self, + file: FileId, + literal: ExprId, + func: FnId, + ) -> TypeId { + let ty = self.type_of_expr(file, literal); + let TypeData::Anon { + origin: + Origin::ObjectLiteral( + _, + _, + is_js_literal, + ObjectLiteralCheck::ForParent, + object_flags, + is_fresh, + ), + mapper, + } = *self.data(ty) + else { + return ty; + }; + let hir = self.hir(file); + let ExprKind::Object(props) = hir[literal].kind else { + return ty; + }; + // `contextuallyCheckFunctionExpressionOrObjectLiteralMethod` ends with `checkSignatureDeclaration`. An accessor is deferred. + let is_typed_with_literal = |f: FnId| { + matches!(hir[f].kind, FnKind::Method | FnKind::Expr) + && hir[f].this_param.is_some() + && hir[f].this_ty(hir).is_none() + }; + let created_by = if is_typed_with_literal(func) { + ObjectLiteralCheck::ForThisParameter(func) + } else if self.is_object_literal_cached_for_parent(file, literal) { + return ty; + } else { + // The call for the first of them contains those for the others. + let first = props.iter().find_map(|p| { + let value = hir[p].value; + match hir.exprs.get(value.idx())?.kind { + ExprKind::Fn(f) if !is_parenthesized(hir, value) => { + is_typed_with_literal(f).then_some(f) + } + _ => None, + } + }); + first.map_or( + ObjectLiteralCheck::ForThis, + ObjectLiteralCheck::ForThisParameter, + ) + }; + self.intern(TypeData::Anon { + origin: Origin::ObjectLiteral( + file, + literal, + is_js_literal, + created_by, + object_flags, + is_fresh, + ), + mapper, + }) + } + + /// Whether the parent of the object literal `e` passes `e` itself to `checkExpressionCached`, so that the type it has for `e` + /// is `links.resolvedType`: `checkDeclarationInitializer`, `getTypeOfVariableOrParameterOrPropertyWorker` for an export + /// assignment, `getAssignmentDeclarationInitializerType` for an assignment to `module.exports` or to a property of `exports`, + /// `checkAndAggregateReturnExpressionTypes`. + fn is_object_literal_cached_for_parent(&self, file: FileId, e: ExprId) -> bool { + use crate::bind::{JsDeclarationKind, assignment_declaration_kind}; + let (hir, bound) = (self.hir(file), self.bound(file)); + let is_returned = |returned: ExprId| { + matches!( + bound.expr_parent[returned.idx()], + Parent::Stmt(s) if s.is_some() && matches!(hir[s].kind, StmtKind::Return(_)) + ) + }; + // `SkipParentheses` + if is_returned(e) { + return true; + } + // `GetRightMostAssignedExpression` + let mut rightmost = e; + while !is_parenthesized(hir, rightmost) + && let Parent::Expr(parent) = bound.expr_parent[rightmost.idx()] + && parent.is_some() + && let ExprKind::Assign { value, .. } = hir[parent].kind + && value == rightmost + { + if matches!( + assignment_declaration_kind(hir, parent), + JsDeclarationKind::ModuleExports | JsDeclarationKind::ExportsProperty(_) + ) { + return true; + } + rightmost = parent; + } + match bound.expr_parent[e.idx()] { + // "`return await` is also safe to unwrap here" + Parent::Expr(parent) => { + parent.is_some() + && matches!(hir[parent].kind, ExprKind::Await(_)) + && is_returned(parent) + && (self.enclosing_fn_of_expr(file, parent)) + .is_some_and(|f| hir[f].flags.contains(Flags::ASYNC)) + } + _ if is_parenthesized(hir, e) => false, + Parent::VarInit(_) + | Parent::ParamDefault(_) + | Parent::PatPropDefault(_) + | Parent::PatElemDefault(_) => true, + Parent::MemberInit(m) => hir[m].init == e, + Parent::Stmt(s) => { + s.is_some() + && matches!( + hir[s].kind, + StmtKind::ExportDefault(_) | StmtKind::ExportAssign(_) + ) + } + _ => false, + } + } + /// `isContextSensitiveFunctionOrObjectLiteralMethod`, which an accessor is not. pub(super) fn is_context_sensitive_function_or_method( &self, @@ -3099,6 +3361,8 @@ impl<'p, 's> Checker<'p, 's> { is_enum: false, stored_under: None, is_array_literal: true, + is_array_pattern: false, + has_other_instantiation: false, }, ) } @@ -3213,7 +3477,10 @@ impl<'p, 's> Checker<'p, 's> { return false; } let symbol = bound.expr_symbol[literal.idx()]; - if symbol.is_some() && !bound.table(bound.symbols[symbol.idx()].exports).is_empty() { + if symbol.is_some() + && matches!(hir[literal].kind, ExprKind::Object(props) if props.is_empty()) + && !bound.table(bound.symbols[symbol.idx()].exports).is_empty() + { return true; } let Some((call, argument)) = self.enclosing_call_argument(file, literal) else { @@ -3284,10 +3551,10 @@ impl<'p, 's> Checker<'p, 's> { return self.create_object_literal_type(file, e, props, object_flags, reads); } // With spreads, its members depend on the spread types, so they are resolved eagerly. - let in_destructuring_pattern = self.is_definite_assignment_target(file, e); let scope = self.enclosing_scope_of_expr(file, e); let literal_mapper = self.identity_mapper_with_adopted(file, scope); - let is_const = self.is_const_context(file, e); + let context = self.object_literal_context(file, e); + let is_const = context.in_const_context; let mut result = TypeId::EMPTY_OBJECT; let mut rank = 0; let mut pending = Shape::new_in(self.arena); @@ -3300,14 +3567,16 @@ impl<'p, 's> Checker<'p, 's> { if let Some(segment) = self.create_object_literal_segment(file, members, &mut pending, is_const) { - result = self.spread_in_literal(result, segment, is_const, &mut rank); + result = self.get_spread_type(result, segment, is_const, &mut rank); } run = p.0 + 1; let spread = self.type_of_expr(file, prop.value); let spread = self.reduced(spread); - // 2698 and `spread = c.errorType`. `check_spread` reports it, but not for a target. + // 2698 and `spread = c.errorType`. `check_spread` reports it, but not for a target + // that is destructured: the walk does not check that one as an expression. if !self.is_valid_spread_type(spread) { - if in_destructuring_pattern && self.is_target_of_assignment_in_progress(file, e) + if self.is_definite_assignment_target(file, e) + && self.is_target_of_assignment_in_progress(file, e) { self.error(file, p, 2698, &[]); } @@ -3324,21 +3593,14 @@ impl<'p, 's> Checker<'p, 's> { if self.is_error_type(result) { continue; } - result = self.spread_in_literal(result, spread, is_const, &mut rank); + result = self.get_spread_type(result, spread, is_const, &mut rank); continue; } object_flags |= self.look_at_member(file, p); let Some(name) = self.name_of_literal_member(file, p) else { continue; }; - let (source, flags) = self.property_of_literal_member(file, p); - // `getSpreadSymbol`: whether an accessor is writable is not copied, that it is - // write-only is. - let mut flags = - flags & (PropFlags::WRITE_ONLY | PropFlags::OPTIONAL | PropFlags::METHOD); - if is_const && !matches!(prop.kind, PropKind::Getter | PropKind::Setter) { - flags |= PropFlags::READONLY; - } + let (source, flags) = self.property_of_literal_member_in(file, p, name, context); pending.props.retain(|x| x.name != name); let is_written = self.has_read_unfinished_type_since(reads); let (source, written) = @@ -3363,7 +3625,7 @@ impl<'p, 's> Checker<'p, 's> { if let Some(segment) = self.create_object_literal_segment(file, members, &mut pending, is_const) { - result = self.spread_in_literal(result, segment, is_const, &mut rank); + result = self.get_spread_type(result, segment, is_const, &mut rank); } result = self.with_symbol_of_literal(file, e, result, object_flags); // "remap the raw emptyObjectType fed in at the top into a fresh empty object literal type, @@ -3396,8 +3658,9 @@ impl<'p, 's> Checker<'p, 's> { let scope = self.enclosing_scope_of_expr(file, e); let mapper = self.identity_mapper_with_adopted(file, scope); let is_js_literal = self.is_js_literal(file, e); + let created_by = ObjectLiteralCheck::ForParent; let kept = self.intern(TypeData::Anon { - origin: Origin::ObjectLiteral(file, e, is_js_literal, false, object_flags, true), + origin: Origin::ObjectLiteral(file, e, is_js_literal, created_by, object_flags, true), mapper, }); if self.is_rechecking() { @@ -3526,9 +3789,16 @@ impl<'p, 's> Checker<'p, 's> { if self.is_context_checked(file, e, func) { return; } - let hir = self.hir(file); + let (hir, bound) = (self.hir(file), self.bound(file)); let f = &hir[func]; - // `getSignaturesOfType(getTypeOfSymbol(..))` creates the signature. + // `getSignaturesOfType(getTypeOfSymbol(..))`: `resolveAnonymousTypeMembers` begins with + // `getExportsOfSymbol`, which binds the names of `f[key] = value`, so under whatever is + // resolving the type of this expression. + let symbol = bound.symbol_of_function(hir, func); + if symbol.is_some() && bound.symbols[symbol.idx()].exports.is_some() { + self.late_bound_members(self.files().sym(file, symbol), true); + } + // It creates the signature. if hir.is_js { self.is_untyped_signature_in_js_file(file, func); } @@ -3574,10 +3844,21 @@ impl<'p, 's> Checker<'p, 's> { && self.untyped_call_resolved_again.is_some_and(|(of, call)| { of == file && self.bound(file).expr_parent[e.idx()] == Parent::Expr(call) }); - let holds = is_argument_of_untyped_call || !self.is_innermost_tainted(); + // What follows from the incomplete type of a loop stays too (`taint_from`): nothing resets + // the flag or `links.resolvedType` of a parameter when the loop is complete. + let is_checked_again = (self.frames.last()) + .is_some_and(|frame| frame.tainted && (!frame.incomplete_flow || frame.drops_reported)); + let holds = is_argument_of_untyped_call || !is_checked_again; self.context_checking.push(((file, func), assigned)); // `assignContextualParameterTypes`, `assignNonContextualParameterTypes` if is_context_sensitive { + // `assignContextualParameterTypes` leaves out a `this` parameter with an annotation. One + // without pushes no resolution here: `type_of_this_parameter` computes it on request. + if contextual_signature.is_none() && f.this_ty(hir).is_some() { + self.assigned_parameters.push(self.stack.len()); + self.type_of_this_parameter(file, func); + self.assigned_parameters.pop(); + } for p in f.params.iter() { self.assigned_parameters.push(self.stack.len()); self.type_of_param(file, p); @@ -3602,8 +3883,23 @@ impl<'p, 's> Checker<'p, 's> { && !(check_mode - CheckMode::SKIP_GENERIC_FUNCTIONS).is_empty(); let q = Query::ReturnAtFirstLook(file, func); let stored = match self.leave(q) { - Err(_) if is_stored_in_flow_loop => self.incomplete_flow_result(q), - left => left.ok(), + Ok(stored) => Some(stored), + Err(open) => { + let left_frame = self.left_frame; + let stored = if is_stored_in_flow_loop { + self.incomplete_flow_result(q) + } else { + None + }; + // No request pushes a resolution for it while what it follows from is in + // progress. + if stored.is_none() { + self.left_frame = left_frame; + let returned = Query::Return(file, func); + self.cache_provisionally(returned, u64::from(ty.0), open); + } + stored + } }; // `if signature.resolvedReturnType == nil`: the first value stays. if let Some(stored) = stored { @@ -3723,7 +4019,7 @@ impl<'p, 's> Checker<'p, 's> { if hir[func].this_ty(hir).is_none() { self.read_this_parameter_of_instantiation(context, &mut read); } - let params = self.sig_params(context); + let params = self.sig_params_assigned_to(context, file, func); let rest = params.last().filter(|p| p.rest); for (i, p) in hir[func].params.iter().enumerate() { if hir[p].ty.is_some() { @@ -3877,6 +4173,17 @@ impl<'p, 's> Checker<'p, 's> { ty }; } + self.check_expression_afresh(file, e, check_mode) + } + + /// `checkExpressionEx`, for a caller that is not rechecking: no stored type is read, and none + /// is stored. + pub(super) fn check_expression_afresh( + &mut self, + file: FileId, + e: ExprId, + check_mode: CheckMode, + ) -> TypeId { // Results computed under one mode are not valid under another. let found_outside = ( std::mem::take(&mut self.rechecked_exprs), @@ -3901,22 +4208,22 @@ impl<'p, 's> Checker<'p, 's> { } // FOR SPEED: `checkSourceElementWorker` has no case for these, and `checkTypeReferenceNode` // without type arguments asks for the type alone. - match self.hir(file)[node].kind { - TypeNodeKind::Ref { args, .. } if args.is_empty() => { - self.type_from_node(file, node); - return; - } + let asks_for_the_type_alone = match self.hir(file)[node].kind { + TypeNodeKind::Ref { args, .. } if args.is_empty() => true, TypeNodeKind::Error - | TypeNodeKind::Heritage(_) + | TypeNodeKind::Heritage { .. } | TypeNodeKind::Keyword(_) | TypeNodeKind::StringLit(_) | TypeNodeKind::NumberLit(_) | TypeNodeKind::BigIntLit { .. } | TypeNodeKind::BoolLit(_) => return, - _ => {} - } - // FOR SPEED: with nothing in resolution the walk asks for the same. - if !self.stack.iter().any(|&q| self.is_resolution(q)) { + // FOR SPEED: with nothing in resolution the walk asks for the rest. + _ => !self.stack.iter().any(|&q| self.is_resolution(q)), + }; + if asks_for_the_type_alone { + let outer = self.looked_at_type_node.replace((file, node)); + self.type_from_node(file, node); + self.looked_at_type_node = outer; return; } let reported = self.reported.len(); @@ -3937,9 +4244,11 @@ impl<'p, 's> Checker<'p, 's> { fn look_at_with(&mut self, check: impl FnOnce(&mut Self)) { // FOR SPEED: with nothing in resolution they ask for the same. if self.stack.iter().any(|&q| self.is_resolution(q)) { - let reported = self.reported.len(); + let (reported, requests) = + (self.reported.len(), self.reported_iteration_requests.len()); check(self); self.reported.truncate(reported); + self.settle_iteration_requests(requests, true); } } @@ -3955,8 +4264,8 @@ impl<'p, 's> Checker<'p, 's> { if !matches!(hir[target].kind, ExprKind::Object(_) | ExprKind::Array(_)) || is_parenthesized(hir, target) { - c.check_assignments_among(file, &[e], Some(source)); - } else if !c.is_definite_assignment_target(file, e) { + c.check_plain_assignment_operator(file, e, Some(source)); + } else if !c.is_assignment_element_with_initializer(file, e) { c.check_destructuring_assignment(file, target, source); } }); @@ -3992,8 +4301,10 @@ impl<'p, 's> Checker<'p, 's> { self.look_at_binding_name(file, param.pat); self.type_of_pat(file, param.pat); } - if param.default.is_some() { - self.look_at_initializer(file, param.default); + if param.default.is_some() + && !self.is_binding_pattern_in_ambient_or_type_node(file, param.pat) + { + self.look_at(file, param.default); self.look_at_with(|c| c.check_parameter_initializer(file, p)); } if is_name && param.flags.contains(Flags::REST) { @@ -4052,22 +4363,12 @@ impl<'p, 's> Checker<'p, 's> { } self.look_at_with(|c| c.check_binding_element_accessibility(file, pattern, name)); self.look_at_binding_name(file, name); - if initializer.is_some() { - self.look_at_initializer(file, initializer); + if initializer.is_some() && !self.is_binding_pattern_in_ambient_or_type_node(file, name) { + self.look_at(file, initializer); self.look_at_with(|c| c.check_binding_element_initializer(file, name, initializer)); } } - /// `checkExpressionCached(initializer)` in `checkVariableLikeDeclaration`, which has no - /// `getQuickTypeOfExpression`. - fn look_at_initializer(&mut self, file: FileId, initializer: ExprId) { - if let ExprKind::As { expr, ty } = self.hir(file)[initializer].kind { - self.look_at(file, expr); - self.look_at_type_node(file, ty); - } - self.look_at(file, initializer); - } - /// `createObjectLiteralType` for the members `run` of an object literal, which are consecutive /// between two spreads. `named` holds those with a statically known name, and is left empty. /// `None`: there are no members there. @@ -4086,53 +4387,11 @@ impl<'p, 's> Checker<'p, 's> { Some(self.synth(std::mem::replace(named, Shape::new_in(self.arena)))) } - /// `getSpreadType`, which in a const context (`readonly`) produces a readonly result. - /// `rank`: see `Shape::spread_rank`. - fn spread_in_literal( - &mut self, - left: TypeId, - right: TypeId, - readonly: bool, - rank: &mut u32, - ) -> TypeId { - let spread = self.get_spread_type(left, right, readonly, rank); - if !readonly { - return spread; - } - self.map_type(spread, |c, m| { - let TypeData::Synth(shape) = c.data(m) else { - return m; - }; - if shape.literal != Literalness::WithSpread { - return m; - } - let mut shape = (**shape).clone_in(self.arena); - for prop in &mut shape.props { - // A property of the left that the right may or may not override is recreated - // without readonly information. - let is_of_both = c.parts(right).iter().any(|&r| { - c.prop_ref(r, prop.name) - .is_some_and(|(p, _)| p.flags.contains(PropFlags::OPTIONAL)) - }) && c - .parts(left) - .iter() - .any(|&l| c.prop_ref(l, prop.name).is_some()); - if !is_of_both { - prop.flags |= PropFlags::READONLY; - } - } - for info in &mut shape.index { - info.readonly = true; - } - c.synth(shape) - }) - } - /// `member.Name` where `checkObjectLiteral` adds the member `p` to `propertiesTable`. It makes a /// new symbol, named after the type of a computed name, for anything but an accessor, which /// keeps `getSymbolOfDeclaration(memberDecl)`. `None`: a name that is only known at run time, /// or `InternalSymbolNameComputed`, which is no property. - fn name_of_literal_member(&mut self, file: FileId, p: PropId) -> Option { + pub(super) fn name_of_literal_member(&mut self, file: FileId, p: PropId) -> Option { let prop = &self.hir(file)[p]; match prop.kind { PropKind::Getter | PropKind::Setter => self.declared_member_name(file, prop.key), @@ -4157,7 +4416,7 @@ impl<'p, 's> Checker<'p, 's> { } /// `getSymbolOfDeclaration(memberDecl).Flags` for the member `p` of an object literal. - fn flags_of_literal_member(&mut self, file: FileId, p: PropId) -> SymFlags { + pub(super) fn flags_of_literal_member(&mut self, file: FileId, p: PropId) -> SymFlags { let (hir, bound) = (self.hir(file), self.bound(file)); let mut flags = SymFlags::empty(); for &(_, declaration) in self.declarations_of_member(file, Decl::Property(p)).iter() { @@ -4186,11 +4445,34 @@ impl<'p, 's> Checker<'p, 's> { { flags |= PropFlags::READONLY; } + // Or a `SymbolFlagsProperty` with the modifier (1042), which + // `getDeclarationModifierFlagsFromSymbol` takes from the getter, else from + // `ValueDeclaration`. + let hir = self.hir(file); + if !hir.modifiers_of_props.is_empty() + && (member_flags.contains(SymFlags::PROPERTY) + || !matches!(hir[p].kind, PropKind::Getter | PropKind::Setter)) + { + let getter = self.accessor_of_literal(file, p, PropKind::Getter); + let declaration = getter.or_else(|| { + let declarations = self.declarations_of_member(file, Decl::Property(p)); + declarations.iter().find_map(|it| match it.1 { + Decl::Property(first) => Some(first), + _ => None, + }) + }); + if declaration.is_some_and(|it| { + let modifiers = hir.modifiers_to_flags(hir.prop_modifiers(it)); + modifiers.contains(Flags::READONLY) + }) { + flags |= PropFlags::READONLY; + } + } // `getSpreadSymbol`: an accessor without a getter, whose copy has type `undefined`. if member_flags & SymFlags::ACCESSOR == SymFlags::SET_ACCESSOR { flags |= PropFlags::WRITE_ONLY; } - match self.hir(file)[p].kind { + match hir[p].kind { PropKind::Getter => (p, flags | PropFlags::ACCESSOR), PropKind::Setter => { let getter = self.accessor_of_literal(file, p, PropKind::Getter); @@ -4204,6 +4486,52 @@ impl<'p, 's> Checker<'p, 's> { } } + /// The start of `checkObjectLiteral`, for the literal `e`. + fn object_literal_context(&mut self, file: FileId, e: ExprId) -> ObjectLiteralContext { + let in_destructuring_pattern = self.is_assignment_target(file, e); + let implied = if self.pattern_that_may_expect(file, e).is_some() { + self.apparent_type_of_contextual_type(file, e, ContextFlags::empty()) + .filter(|&context| self.pattern_of_type(context) == Some(false)) + } else { + None + }; + ObjectLiteralContext { + in_destructuring_pattern, + implied, + in_const_context: self.is_const_context(file, e), + } + } + + /// `property_of_literal_member`, with what the new symbol gets from the context of the literal. + /// An accessor keeps its symbol. + fn property_of_literal_member_in( + &mut self, + file: FileId, + p: PropId, + name: Atom, + context: ObjectLiteralContext, + ) -> (PropId, PropFlags) { + let (source, mut flags) = self.property_of_literal_member(file, p); + if flags.contains(PropFlags::ACCESSOR) { + return (source, flags); + } + if context.in_const_context { + flags |= PropFlags::READONLY; + } + let value = self.hir(file)[p].value; + if context.in_destructuring_pattern + && value.is_some() + && self.has_default_value(file, value) + || context.implied.is_some_and(|implied| { + self.prop_ref(implied, name) + .is_some_and(|(p, _)| p.flags.contains(PropFlags::OPTIONAL)) + }) + { + flags |= PropFlags::OPTIONAL; + } + (source, flags) + } + /// `getOptionalSymbolFlagForNode`: whether `p` is a method of an object literal declared as /// `name?() {}` (1162). pub(super) fn is_optional_method(&self, file: FileId, p: PropId) -> bool { @@ -4367,15 +4695,7 @@ impl<'p, 's> Checker<'p, 's> { let ExprKind::Object(props) = hir[e].kind else { return Shape::new_in(self.arena); }; - let is_const = self.is_const_context(file, e); - let in_pattern = self.is_definite_assignment_target(file, e); - // `patternForType`: the type a pattern without computed names implies for the literal. - let implied = if self.pattern_that_may_expect(file, e).is_some() { - self.apparent_type_of_contextual_type(file, e, ContextFlags::empty()) - .filter(|&context| self.pattern_of_type(context) == Some(false)) - } else { - None - }; + let context = self.object_literal_context(file, e); let mut shape = Shape::new_in(self.arena); shape.props.reserve_exact(props.len()); // The names of `shape.props`, of a literal with many members. @@ -4386,33 +4706,11 @@ impl<'p, 's> Checker<'p, 's> { } let mut has_repeated_name = false; for p in props.iter() { - let prop = &hir[p]; let Some(name) = self.name_of_literal_member(file, p) else { continue; }; - let (source, mut flags) = self.property_of_literal_member(file, p); + let (source, flags) = self.property_of_literal_member_in(file, p, name, context); let is_accessor = flags.contains(PropFlags::ACCESSOR); - if !is_accessor { - // `checkObjectLiteral`: accessors have their declared type in any context. - if is_const { - flags |= PropFlags::READONLY; - } - // `hasDefaultValue`: a property with a default in an assignment pattern is - // optional. So is a property for which the pattern the literal is assigned to - // has a default. - let has_default = in_pattern - && prop.value.is_some() - && matches!(hir[prop.value].kind, ExprKind::Assign { op: None, .. }) - && !is_parenthesized(hir, prop.value); - if has_default - || implied.is_some_and(|implied| { - self.prop_ref(implied, name) - .is_some_and(|(p, _)| p.flags.contains(PropFlags::OPTIONAL)) - }) - { - flags |= PropFlags::OPTIONAL; - } - } // `propertiesTable[member.Name] = member`: the last member with the name is the property. let may_exist = !has_many || !names.insert(name); if may_exist && let Some(existing) = shape.props.iter().position(|x| x.name == name) { @@ -4434,11 +4732,12 @@ impl<'p, 's> Checker<'p, 's> { mapper: MapperId::IDENTITY, }); } - // The binder adds a declaration to the symbol of that name where it can. - if has_repeated_name { + // FOR SPEED: in any other literal every member is the first declaration of its symbol. The binder adds a declaration to the + // symbol of that name where it can, and so does `bindThisPropertyAssignment`. + if has_repeated_name || hir.is_js && self.bound(file).expr_symbol[e.idx()].is_some() { self.get_named_members(&mut shape.props, |_| true, &[]); } - shape.index = self.index_infos_of_object_literal(file, props, is_const); + shape.index = self.index_infos_of_object_literal(file, props, context.in_const_context); // "Expando object literals have empty properties but filled exports" let owner = self.bound(file).expr_symbol[e.idx()]; self.with_expandos(shape, file, owner) @@ -4468,8 +4767,9 @@ impl<'p, 's> Checker<'p, 's> { owner } Parent::Expr(parent) => match hir[parent].kind { + // `getContextualTypeForBinaryOperand` ExprKind::Assign { - op: None, + op: None | Some(BinOp::And | BinOp::Or | BinOp::Nullish), target, value, } if value == at => { @@ -4530,7 +4830,7 @@ impl<'p, 's> Checker<'p, 's> { } if !self.enter(Query::LiteralProp(file, p)) { // `getTypeOfAccessors` - return if self.found_cycle { + return if self.found_cycle || self.is_getter_in_cycle(file, p) { TypeId::ERROR } else { TypeId::UNRESOLVED @@ -4560,6 +4860,17 @@ impl<'p, 's> Checker<'p, 's> { } } + /// Whether `pushTypeResolution` of `getTypeOfAccessors` fails for the getter `p`, which is in + /// progress: `Query::Return` stands for that resolution. + fn is_getter_in_cycle(&self, file: FileId, p: PropId) -> bool { + let hir = self.hir(file); + hir[p].kind == PropKind::Getter + && hir[p].value.is_some() + && matches!(hir[hir[p].value].kind, ExprKind::Fn(getter) + if (self.stack.iter().rposition(|&q| q == Query::Return(file, getter))) + .is_some_and(|at| self.frames[at].circular)) + } + /// `checkPropertyAssignment`, `checkShorthandPropertyAssignment` and `checkObjectLiteralMethod` /// have no re-entrancy guard either: `recheck_in_flow_loop` for the member `p`. An accessor has /// one (`getTypeOfAccessors`). diff --git a/src/sema/check/flow.rs b/src/sema/check/flow.rs index dce7cbd2e164..28ae8d83dc5c 100644 --- a/src/sema/check/flow.rs +++ b/src/sema/check/flow.rs @@ -12,8 +12,16 @@ use crate::bind::{ }; use smallvec::{SmallVec, smallvec}; +/// See `Checker::access_key`. +#[derive(Copy, Clone)] +pub(super) enum AccessKey { + Name(Atom), + /// `this[k]`, where `k` has no literal type: a variable whose value never changes (`is_constant_key`). + Variable(Root), +} + #[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum Root { +pub(super) enum Root { Symbol(SymbolId), /// A name that is not declared in the file. Global(Atom), @@ -21,8 +29,8 @@ enum Root { Super, /// `import.meta` ImportMeta, - /// `new.target` - NewTarget, + /// `new.target`, or whatever name follows `new.` + NewTarget(Atom), /// The value a pattern destructures. No expression refers to it. Tests of the variables the /// pattern binds narrow it. Pattern(PatId), @@ -34,23 +42,74 @@ enum Root { Other, } +/// `getAccessedPropertyName` of an access in a reference. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum AccessedName { + Some(Atom), + None, + /// Of `[k]`, for this `k`: nothing has asked for it yet, and `literal_key` may resolve a type. + Unresolved(ExprId), +} + +impl From> for AccessedName { + fn from(name: Option) -> AccessedName { + name.map_or(AccessedName::None, AccessedName::Some) + } +} + +/// `.name` or `[k]` in a reference. +#[derive(Clone, Debug)] +struct Step { + /// See `name_of_step`. + name: std::cell::Cell, + /// What `k` names, if it is an identifier: `isMatchingReference` compares the symbols of two + /// keys that do not both have a name. `Root::Other`: it matches no key. + variable: Root, +} + +impl Step { + fn named(name: Atom) -> Step { + Step { + name: std::cell::Cell::new(AccessedName::Some(name)), + variable: Root::Other, + } + } +} + +/// As `writeFlowCacheKey` writes them, which resolves the names. +impl PartialEq for Step { + fn eq(&self, other: &Self) -> bool { + match (self.name.get(), other.name.get()) { + (AccessedName::None, AccessedName::None) => self.variable == other.variable, + (a, b) => a == b, + } + } +} + /// `x`, `this`, `x.a.b`: something whose type can be narrowed. #[derive(Clone, Debug)] pub(super) struct Reference { file: FileId, root: Root, - /// `Atom::NONE` for `[k]` where `path_key` has no key for `k`: it matches nothing. - path: SmallVec<[Atom; 4]>, + path: SmallVec<[Step; 4]>, + /// How many names in `path` are `AccessedName::Unresolved`. + unresolved: std::cell::Cell, /// Its expression, if it has one. Two references at different positions are the same reference. at: ExprId, - /// `getFlowReferenceKey` has a key for it. It has none for what starts at `super`, `import.meta` or `new.target`, or goes - /// through a comma, a `satisfies` or an assignment. See `has_flow_reference_key`. + /// If it has none: the pattern, the function or the name it is, or the parent of the node that + /// is synthesized for it. + node: Node, + /// `writeFlowCacheKey` gets to its root and has a key for that. Not for `super`, `import.meta` + /// or `new.target`. See `has_flow_reference_key`. has_key: bool, - /// It goes through a `satisfies`, which `isMatchingReference` looks through in its source only. - has_satisfies: bool, - /// How many steps of `path` are inside the outermost assignment it goes through: 1 for - /// `(o.x = v).y`. `isMatchingReference` looks through an assignment in its target only. - /// `usize::MAX`: it goes through none. + /// How many steps of `path` are inside the outermost comma, `satisfies` or assignment it goes + /// through, where `writeFlowCacheKey` fails. `usize::MAX`: it goes through none. + unkeyed: usize, + /// The same for the outermost `satisfies`: 0 for `(o satisfies T).y`. `isMatchingReference` + /// looks through one in its source only. + satisfies: usize, + /// The same for the outermost assignment: 1 for `(o.x = v).y`. `isMatchingReference` looks + /// through one in its target only. assigned: usize, /// How many access expressions follow each other from the outermost one inwards, with no `!` /// and no parentheses in between: `containsMatchingReference` goes no further. None for the @@ -59,16 +118,19 @@ pub(super) struct Reference { } impl Reference { - /// A reference that does not occur in the source: `root`, or `root.a.b`. - fn synthetic(file: FileId, root: Root, path: SmallVec<[Atom; 4]>) -> Reference { + /// A reference that is no expression of the source: `root`, or `root.a.b`. + fn synthetic(file: FileId, root: Root, path: SmallVec<[Step; 4]>, node: Node) -> Reference { Reference { file, root, accesses: path.len(), path, + unresolved: std::cell::Cell::new(0), at: ExprId::NONE, + node, has_key: true, - has_satisfies: false, + unkeyed: usize::MAX, + satisfies: usize::MAX, assigned: usize::MAX, } } @@ -150,6 +212,9 @@ pub(super) struct FlowMemo { flow_loop_cached_at: u64, /// `switchStatementLinks` switch_statement_links: FxHashMap<(FileId, StmtId), SwitchStatementLinks>, + /// `contextFreeTypes`, for the results that depend on the incomplete type of a loop in + /// progress. The others are in `Program::context_free_expr_types`. + context_free_types_in_loops: FxHashMap<(FileId, ExprId), TypeId>, /// The depth of `stack` when each `ExhaustiveState::Computing` was set, the innermost last. exhaustive_states_computing: SmallVec<[usize; 2]>, /// `has_order_dependent_assignment_marks`, by file, and for the file that was asked about last. @@ -336,6 +401,8 @@ enum Start { struct Walk { reference: Reference, + /// `refKey != nonDottedNameCacheKey`. `None`: no loop label has asked for it yet. + has_reference_key: Option, declared: TypeId, /// The type of the reference where the walk ends without reaching an assignment. See /// `initial_of`. @@ -368,7 +435,7 @@ fn root_key(root: Root) -> u32 { Root::This => 3, Root::Super | Root::ImportMeta - | Root::NewTarget + | Root::NewTarget(_) | Root::Pattern(_) | Root::Params(_) | Root::Other => 0, @@ -512,7 +579,10 @@ impl About { let Some(first) = reference.path.first() else { return self.chains.iter().any(|chain| chain.0 == root); }; - let first = first.0.wrapping_add(1); + let first = match first.name.get() { + AccessedName::Some(name) => name.0.wrapping_add(1), + AccessedName::None | AccessedName::Unresolved(_) => 0, + }; self.chains .iter() .any(|chain| chain.0 == root && (chain.1 == 0 || chain.1 == first)) @@ -654,6 +724,7 @@ impl Walk { ) -> Walk { Walk { reference, + has_reference_key: None, declared, initial, start: Start::Known, @@ -691,13 +762,20 @@ struct Access { non_null: bool, } -/// What distinguishes `a[index]` from `a[other]`. +/// The constant or enum member that `tryGetNameFromEntityNameExpression` takes a name from. #[derive(Copy, Clone)] -enum AccessKey { - /// `getAccessedPropertyName`, or the key of a constant of another script or of the library. - Name(Atom), - /// The variable or parameter of the file that `index` names. It is a key if `is_constant_name`. - Variable(SymbolId), +struct KeyConstant { + sym: Sym, + /// The file of `symbol.ValueDeclaration`, and that. + file: FileId, + declaration: Node, + /// The name of a variable declaration. + variable: Option, + /// `declaration.Type()` + annotation: TypeNodeId, + initializer: ExprId, + /// The name of an enum member. + member_name: Atom, } /// `IsFunctionOrSourceFile` @@ -1121,52 +1199,55 @@ impl<'p, 's> Checker<'p, 's> { // ───────────────────────────── references ───────────────────────────── + /// What the identifier `e` names, as the root of a reference or as a key. + #[inline] + fn root_of_identifier(&self, file: FileId, e: ExprId, name: Atom) -> Root { + let symbol = self.bound(file).expr_symbol[e.idx()]; + if symbol.is_none() { + Root::Global(name) + } else { + Root::Symbol(symbol) + } + } + /// `e` as the reference of a walk. `isNarrowableReference` gives a flow node to more than what /// can be narrowed: the walk for `f()["a"]` or `(o.x = v).y` evaluates what it passes too. pub(super) fn reference_of(&mut self, file: FileId, e: ExprId) -> Reference { let hir = self.hir(file); - let mut path: SmallVec<[Atom; 4]> = SmallVec::new(); + let mut path: SmallVec<[Step; 4]> = SmallVec::new(); let mut at = e; - let (mut has_key, mut has_satisfies) = (true, false); let (mut accesses, mut is_access) = (0, true); - // The number of steps outside the outermost assignment. - let mut unassigned = usize::MAX; + let mut unresolved = 0; + // The number of steps outside the outermost assignment, outside the outermost `satisfies`, + // and outside the outermost of these and the commas. + let (mut unassigned, mut unsatisfied, mut keyed) = (usize::MAX, usize::MAX, usize::MAX); let root = loop { is_access = is_access && matches!(hir[at].kind, ExprKind::Dot { .. } | ExprKind::Index { .. }) && (at == e || !is_parenthesized(hir, at)); accesses += is_access as usize; match hir[at].kind { - ExprKind::Ident(name) => { - let symbol = self.bound(file).expr_symbol[at.idx()]; - break if symbol.is_none() { - Root::Global(name) - } else { - Root::Symbol(symbol) - }; - } + ExprKind::Ident(name) => break self.root_of_identifier(file, at, name), ExprKind::This => break Root::This, ExprKind::Super => break Root::Super, ExprKind::ImportMeta => break Root::ImportMeta, - ExprKind::NewTarget(_) => break Root::NewTarget, + ExprKind::NewTarget(name) => break Root::NewTarget(name), ExprKind::Dot { obj, name, .. } => { - path.push(name); + path.push(Step::named(name)); at = obj; } ExprKind::Index { obj, index, .. } => { - // FOR SPEED: whether the variable of `[k]` is constant is asked here, once. - // `isMatchingReference` and `writeFlowCacheKey` ask when they get to it. - let is_asked_later = self.has_order_dependent_assignment_marks(file); - let key = self.path_key(file, index, is_asked_later); - has_key &= key.is_some(); - path.push(key.unwrap_or(Atom::NONE)); + let step = self.step_of_element_access(file, index); + unresolved += u32::from(matches!(step.name.get(), AccessedName::Unresolved(_))); + path.push(step); at = obj; } ExprKind::NonNull(x) => at = x, // `isMatchingReference` looks through these when they occur in the narrowed // reference. `writeFlowCacheKey` handles none of them. ExprKind::Satisfies { expr: x, .. } => { - (has_key, has_satisfies) = (false, true); + unsatisfied = unsatisfied.min(path.len()); + keyed = keyed.min(path.len()); at = x; } ExprKind::Binary { @@ -1174,35 +1255,108 @@ impl<'p, 's> Checker<'p, 's> { right: x, .. } => { - has_key = false; + keyed = keyed.min(path.len()); at = x; } ExprKind::Assign { target, .. } => { - has_key = false; unassigned = unassigned.min(path.len()); + keyed = keyed.min(path.len()); at = target; } _ => break Root::Other, } }; path.reverse(); - let has_key = has_key + let inside = |outside: usize| path.len().checked_sub(outside).unwrap_or(usize::MAX); + let (unkeyed, satisfies, assigned) = + (inside(keyed), inside(unsatisfied), inside(unassigned)); + let has_key = unkeyed == usize::MAX && !matches!( root, - Root::Super | Root::ImportMeta | Root::NewTarget | Root::Other + Root::Super | Root::ImportMeta | Root::NewTarget(_) | Root::Other ); Reference { file, root, - assigned: path.len().checked_sub(unassigned).unwrap_or(usize::MAX), path, + unresolved: std::cell::Cell::new(unresolved), at: e, + node: Node::NONE, has_key, - has_satisfies, + unkeyed, + satisfies, + assigned, accesses, } } + /// `Step::variable` of `[index]`. + fn variable_of_key(&self, file: FileId, index: ExprId) -> Root { + let hir = self.hir(file); + match hir[index].kind { + ExprKind::Ident(name) if !is_parenthesized(hir, index) => { + self.root_of_identifier(file, index, name) + } + _ => Root::Other, + } + } + + /// `[index]` as a step of a reference. + fn step_of_element_access(&mut self, file: FileId, index: ExprId) -> Step { + let hir = self.hir(file); + let is_entity_name = matches!(hir[index].kind, ExprKind::Ident(_) | ExprKind::Dot { .. }) + && !is_parenthesized(hir, index); + let name: AccessedName = if !is_entity_name { + self.literal_key(file, index).into() + } else { + match self.key_constant(file, index) { + None => AccessedName::None, + // FOR SPEED: a name that is found without resolving a type is found at once. + Some(constant) if self.is_name_of_key_constant_settled(&constant) => { + self.name_of_key_constant(file, index, &constant).into() + } + Some(_) => AccessedName::Unresolved(index), + } + }; + let mut variable = self.variable_of_key(file, index); + // FOR SPEED: whether the variable of `[k]` is constant is asked here, once. + // `isMatchingReference` and `writeFlowCacheKey` ask when they get to it. + if name == AccessedName::None + && !self.has_order_dependent_assignment_marks(file) + && !self.is_constant_key(file, variable) + { + variable = Root::Other; + } + Step { + name: std::cell::Cell::new(name), + variable, + } + } + + /// `getAccessedPropertyName` of the access `reference.path[step]`. + #[inline] + fn name_of_step(&mut self, reference: &Reference, step: usize) -> Option { + match reference.path[step].name.get() { + AccessedName::Some(name) => Some(name), + AccessedName::None => None, + AccessedName::Unresolved(index) => self.resolve_name_of_step(reference, step, index), + } + } + + #[cold] + fn resolve_name_of_step( + &mut self, + reference: &Reference, + step: usize, + index: ExprId, + ) -> Option { + let name = self.literal_key(reference.file, index); + reference.path[step].name.set(name.into()); + let unresolved = reference.unresolved.get(); + reference.unresolved.set(unresolved.saturating_sub(1)); + name + } + /// `tryGetElementAccessExpressionName`: the property `a[index]` names, if the syntax determines /// it, or if a constant that represents a single name does. A parenthesized key yields nothing. pub(super) fn literal_key(&mut self, file: FileId, index: ExprId) -> Option { @@ -1222,6 +1376,12 @@ impl<'p, 's> Checker<'p, 's> { /// `tryGetNameFromEntityNameExpression` fn name_from_entity_name_expression(&mut self, file: FileId, node: ExprId) -> Option { + let constant = self.key_constant(file, node)?; + self.name_of_key_constant(file, node, &constant) + } + + /// `tryGetNameFromEntityNameExpression`, as far as it resolves no type. + fn key_constant(&self, file: FileId, node: ExprId) -> Option { let sym = self.resolve_entity_name_expression(file, node, SymFlags::VALUE)?; let files = self.files(); let flags = files.flags(sym); @@ -1239,172 +1399,173 @@ impl<'p, 's> Checker<'p, 's> { ) }; let hir = self.hir(of); - let (declaration, annotated, initializer) = match decl { - Decl::EnumMember(m) => (hir.node(m), None, hir[m].init), + match decl { + Decl::EnumMember(m) => Some(KeyConstant { + sym, + file: of, + declaration: hir.node(m), + variable: None, + annotation: TypeNodeId::NONE, + initializer: hir[m].init, + member_name: hir[m].name, + }), Decl::Var(pat) => { // Not a variable bound by a pattern. let PatParent::Var(d) = self.bound(of).pat_parent[pat.idx()] else { return None; }; - (hir.node(d), hir[d].ty.is_some().then_some(pat), hir[d].init) + Some(KeyConstant { + sym, + file: of, + declaration: hir.node(d), + variable: Some(pat), + annotation: hir[d].ty, + initializer: hir[d].init, + member_name: Atom::NONE, + }) } - _ => return None, + _ => None, + } + } + + /// Not in tsgo. Whether `name_of_key_constant` finds every type it asks for in a table. + fn is_name_of_key_constant_settled(&mut self, constant: &KeyConstant) -> bool { + let (of, initializer) = (constant.file, constant.initializer); + let annotation = (of, constant.annotation); + let is_resolved = match constant.variable { + Some(_) if constant.annotation.is_some() => self + .p + .type_node_types + .get(&self.task, &annotation) + .is_some(), + Some(pat) => self.p.pat_types.get(&self.task, &(of, pat)).is_some(), + None => true, }; - if let Some(pat) = annotated { - let ty = self.type_of_pat(of, pat); + is_resolved + && (initializer.is_none() + || matches!( + self.hir(of)[initializer].kind, + ExprKind::String(_) | ExprKind::Number(_) + ) + || self.cached_type_of_expr(of, initializer).is_some()) + } + + /// The rest of `tryGetNameFromEntityNameExpression`. + fn name_of_key_constant( + &mut self, + file: FileId, + node: ExprId, + constant: &KeyConstant, + ) -> Option { + let (of, initializer) = (constant.file, constant.initializer); + // `tryGetTypeFromTypeNode(declaration)`, which pushes no resolution of the constant. + if constant.annotation.is_some() { + let ty = self.type_from_node(of, constant.annotation); if let Some(name) = self.property_name_of_type(ty) { return Some(name); } } // A declaration in another file counts as declared. - if of == file - && !self.is_block_scoped_name_declared_before_use(file, declaration, hir.node(node)) - { - return None; + if of == file { + let usage = self.hir(file).node(node); + if !self.is_block_scoped_name_declared_before_use(file, constant.declaration, usage) { + return None; + } } if initializer.is_none() { // An enum member yields its name, not its assigned number. - return match decl { - Decl::EnumMember(m) if hir[m].name.is_some() => Some(hir[m].name), - _ => None, - }; + return (constant.member_name.is_some()).then_some(constant.member_name); } // `getTypeOfExpression` of the initializer, even next to an annotation that does not // resolve. It pushes no resolution of the constant and is not widened. The declaration // creates the unique symbol type of `Symbol()`, from the syntax alone // (`getESSymbolLikeTypeForNode`). - let ty = if matches!(decl, Decl::Var(_)) - && annotated.is_none() + let ty = if constant.variable.is_some() + && constant.annotation.is_none() && self.is_symbol_or_symbol_for_call(of, initializer) { - self.type_of_symbol(sym) + self.type_of_symbol(constant.sym) } else { self.get_type_of_expression(of, initializer) }; self.property_name_of_type(ty) } - /// The name of `a[index]`, or else the variable that `index` is. - fn key_of_element_access(&mut self, file: FileId, index: ExprId) -> Option { - if let Some(name) = self.literal_key(file, index) { - return Some(AccessKey::Name(name)); - } - let hir = self.hir(file); - let ExprKind::Ident(name) = hir[index].kind else { - return None; - }; - if is_parenthesized(hir, index) { - return None; - } - let symbol = self.bound(file).expr_symbol[index.idx()]; - if symbol.is_none() { - // A constant of another script or of the library. - let sym = self - .files() - .global(name, SymFlags::VALUE) - .filter(|&sym| self.files().flags(sym).contains(SymFlags::CONST))?; - let (file, id) = (sym.file.0.to_le_bytes(), sym.id.0.to_le_bytes()); - let key = [&[0][..], &file[..], &id[..]].concat(); - return Some(AccessKey::Name(self.atoms().intern(&key))); - } - self.name_of_value_declaration(file, symbol)?; - Some(AccessKey::Variable(symbol)) - } - - /// A zero byte, and the number of the symbol: it cannot collide with a property name. - fn bytes_of_variable_key(variable: SymbolId) -> [u8; 5] { - let [a, b, c, d] = variable.0.to_le_bytes(); - [0, a, b, c, d] + /// `isConstantVariable` of a name that is not declared in the file: a constant of another + /// script or of the library. + fn is_global_constant(&self, name: Atom) -> bool { + let files = self.files(); + files + .global(name, SymFlags::VALUE) + .is_some_and(|sym| files.flags(sym).contains(SymFlags::CONST)) } - /// The key of `a[index]` in `Reference::path`: the name, or else the variable. - /// `isMatchingReference`: a constant, or a parameter, a `catch` binding or a local `let` that - /// is never assigned. `is_asked_later`: any variable. - fn path_key(&mut self, file: FileId, index: ExprId, is_asked_later: bool) -> Option { - match self.key_of_element_access(file, index)? { - AccessKey::Name(name) => Some(name), - AccessKey::Variable(variable) => { - let is_key = is_asked_later || self.is_constant_name(file, variable); - is_key.then(|| self.atoms().intern(&Self::bytes_of_variable_key(variable))) + /// `isMatchingReference`, `writeFlowCacheKey`: whether `variable`, a `Step::variable`, is a + /// constant, or a parameter, a `catch` binding or a local `let` that is never assigned. + fn is_constant_key(&self, file: FileId, variable: Root) -> bool { + match variable { + Root::Symbol(symbol) => { + self.name_of_value_declaration(file, symbol).is_some() + && self.is_constant_name(file, symbol) } + Root::Global(name) => self.is_global_constant(name), + _ => false, } } - /// The key that distinguishes `a[index]` from `a[other]`: the name, or else the variable, if - /// its value never changes. - pub(super) fn access_key(&mut self, file: FileId, index: ExprId) -> Option { - self.path_key(file, index, false) + /// What distinguishes `this[index]` from `this[other]`, for `is_assigned_in_constructor`. + pub(super) fn access_key(&mut self, file: FileId, index: ExprId) -> Option { + if let Some(name) = self.literal_key(file, index) { + return Some(AccessKey::Name(name)); + } + let variable = self.variable_of_key(file, index); + (self.is_constant_key(file, variable)).then_some(AccessKey::Variable(variable)) } /// `writeFlowCacheKey`, only its calls of `writeSymbol`: for the leftmost identifier, then for /// the variable of each `[k]`. A key that fails has written none. fn get_symbol_ids_of_flow_reference(&mut self, reference: &Reference) { - if !reference.has_key { - return; - } - let file = reference.file; - let leftmost = match reference.root { - Root::Symbol(symbol) => Some(self.files().sym(file, symbol)), - Root::Global(name) => self.files().global(name, SymFlags::VALUE), - _ => None, - }; - if let Some(leftmost) = leftmost { - self.get_symbol_id(leftmost); - } - let hir = self.hir(file); - let (mut at, mut variables) = (reference.at, SmallVec::<[SymbolId; 2]>::new()); - while at.is_some() { - at = match hir[at].kind { - ExprKind::NonNull(x) => x, - ExprKind::Dot { obj, .. } => obj, - ExprKind::Index { obj, index, .. } => { - if let Some(AccessKey::Variable(variable)) = - self.key_of_element_access(file, index) - { - variables.push(variable); - } - obj - } - _ => break, + let unnamed = |step: &&Step| step.name.get() == AccessedName::None; + let variables = reference.path.iter().filter(unnamed); + for written in std::iter::once(reference.root).chain(variables.map(|step| step.variable)) { + let symbol = match written { + Root::Symbol(symbol) => Some(self.files().sym(reference.file, symbol)), + Root::Global(name) => self.files().global(name, SymFlags::VALUE), + _ => None, }; - } - for &variable in variables.iter().rev() { - self.get_symbol_id(self.files().sym(file, variable)); + if let Some(symbol) = symbol { + self.get_symbol_id(symbol); + } } } /// `getFlowReferenceKey(f) != nonDottedNameCacheKey` fn has_flow_reference_key(&mut self, reference: &Reference) -> bool { - let file = reference.file; - if reference.at.is_some() && self.has_order_dependent_assignment_marks(file) { - // `writeFlowCacheKey` asks about the variable of `[k]` before it goes on to the object. - let hir = self.hir(file); - let mut at = reference.at; - loop { - at = match hir[at].kind { - ExprKind::NonNull(x) => x, - ExprKind::Dot { obj, .. } => obj, - ExprKind::Index { obj, index, .. } => { - match self.key_of_element_access(file, index) { - Some(AccessKey::Name(_)) => obj, - Some(AccessKey::Variable(variable)) - if self.is_constant_name(file, variable) => - { - obj - } - _ => return false, - } - } - _ => break, - }; + let unkeyed = match reference.unkeyed { + usize::MAX => 0, + unkeyed => unkeyed, + }; + // `writeFlowCacheKey` asks about `[k]` before it goes on to the object. + for step in (unkeyed..reference.path.len()).rev() { + if self.name_of_step(reference, step).is_none() + && !self.is_constant_key(reference.file, reference.path[step].variable) + { + return false; } } reference.has_key } - /// Whether `e` is the first `len` steps of `reference`: `isMatchingReference`. The source is - /// the reference, or `e` if `is_source`. `satisfies` is looked through in the source only, an - /// assignment in the target only. + /// `getResolvedSymbol(target)`, with its errors, for one of `unchecked_assignment_targets`. + #[cold] + fn resolve_unchecked_assignment_target(&mut self, file: FileId, target: ExprId, name: Atom) { + if self.symbol_of_identifier(file, target, name).is_none() { + self.note_unresolved_identifier(file, target, name); + } + } + + /// `isMatchingReference` of `e` and the first `len` steps of `reference`. The source is the + /// reference, or `e` if `is_source`. fn matches_prefix( &mut self, reference: &Reference, @@ -1412,57 +1573,60 @@ impl<'p, 's> Checker<'p, 's> { e: ExprId, is_source: bool, ) -> bool { - if is_source && reference.has_satisfies { - return false; - } - let hir = self.hir(reference.file); - let mut at = e; - let mut remaining = len; + let file = reference.file; + let hir = self.hir(file); + let (mut at, mut remaining) = (e, len); loop { + // Here the reference is an assignment, which is looked through in the target only. if !is_source && remaining == reference.assigned { return false; } + // Here it is an access, and not a `satisfies`, which is looked through in the source + // only. + let is_access = remaining != 0 && !(is_source && remaining == reference.satisfies); match hir[at].kind { - ExprKind::Ident(name) => { - let symbol = self.bound(reference.file).expr_symbol[at.idx()]; - return remaining == 0 - && reference.root - == if symbol.is_none() { - Root::Global(name) - } else { - Root::Symbol(symbol) - }; - } - ExprKind::This => return remaining == 0 && reference.root == Root::This, - ExprKind::Super => return remaining == 0 && reference.root == Root::Super, - ExprKind::ImportMeta => { - return remaining == 0 && reference.root == Root::ImportMeta; - } - ExprKind::NewTarget(_) => { - return remaining == 0 && reference.root == Root::NewTarget; - } + ExprKind::NonNull(x) => at = x, + ExprKind::Assign { target, .. } if !is_source => at = target, + ExprKind::Satisfies { expr, .. } if is_source => at = expr, + ExprKind::Binary { + op: BinOp::Comma, + right, + .. + } => at = right, + ExprKind::Binary { .. } | ExprKind::Assign { .. } => return false, ExprKind::Dot { obj, name, .. } => { - if remaining == 0 || reference.path[remaining - 1] != name { + if !is_access || self.name_of_step(reference, remaining - 1) != Some(name) { return false; } remaining -= 1; at = obj; } ExprKind::Index { obj, index, .. } => { - // The name of the target's key is resolved once the source's key has one. - if remaining == 0 || !is_source && reference.path[remaining - 1].is_none() { + // The name of the source is asked for first, whatever the target is. That of + // the target once the source has one. + let source = if is_source { + self.literal_key(file, index) + } else if is_access { + self.name_of_step(reference, remaining - 1) + } else { + None + }; + if !is_access { return false; } - let key = reference.path[remaining - 1]; - let is_same_key = match self.key_of_element_access(reference.file, index) { - Some(AccessKey::Name(name)) => name == key, + let target = match source { + None => None, + Some(_) if is_source => self.name_of_step(reference, remaining - 1), + Some(_) => self.literal_key(file, index), + }; + let is_same_key = if target.is_some() { + source == target + } else { // The same variable, and then whether it is constant. - Some(AccessKey::Variable(variable)) => { - key.is_some() - && self.atoms().bytes(key) == Self::bytes_of_variable_key(variable) - && self.is_constant_name(reference.file, variable) - } - None => false, + let variable = reference.path[remaining - 1].variable; + variable != Root::Other + && variable == self.variable_of_key(file, index) + && self.is_constant_key(file, variable) }; if !is_same_key { return false; @@ -1470,14 +1634,28 @@ impl<'p, 's> Checker<'p, 's> { remaining -= 1; at = obj; } - ExprKind::NonNull(x) => at = x, - ExprKind::Assign { target, .. } if !is_source => at = target, - ExprKind::Satisfies { expr, .. } if is_source => at = expr, - ExprKind::Binary { - op: BinOp::Comma, - right, - .. - } => at = right, + _ if remaining != 0 => { + if !is_source { + self.name_of_step(reference, remaining - 1); + } + return false; + } + _ if is_source && reference.satisfies == 0 => return false, + ExprKind::Ident(name) => { + let root = self.root_of_identifier(file, at, name); + // FOR SPEED: `checkSourceFile` resolves every other identifier too. + if matches!(root, Root::Global(_)) + && matches!(reference.root, Root::Symbol(_) | Root::Global(_)) + && (self.bound(file).unchecked_assignment_targets).contains(&at) + { + self.resolve_unchecked_assignment_target(file, at, name); + } + return reference.root == root; + } + ExprKind::This => return reference.root == Root::This, + ExprKind::Super => return reference.root == Root::Super, + ExprKind::ImportMeta => return reference.root == Root::ImportMeta, + ExprKind::NewTarget(name) => return reference.root == Root::NewTarget(name), _ => return false, } } @@ -1490,7 +1668,8 @@ impl<'p, 's> Checker<'p, 's> { /// Whether an entry of `flow_loops` pushed when `stack` had `depth` frames is on `flowLoopStack` now. `checkExpressionCached` /// empties `flowLoopStack`, and it computes what a resolution caches: a resolution entered since the push hides the entry. - /// Not while `checkDeclarationInitializer` has the type from `getQuickTypeOfExpression`, which checks the callee uncached. + /// Not while `checkDeclarationInitializer` has the type from `getQuickTypeOfExpression`, which checks the callee uncached, nor + /// in the resolution of a `...rest`, for which it checks the initializer uncached (`CheckModeRestBindingElement`). pub(super) fn is_flow_loop_visible(&self, depth: usize) -> bool { let depth = depth.min(self.stack.len()); !self.stack[depth..].iter().enumerate().any(|(i, &q)| { @@ -1499,6 +1678,16 @@ impl<'p, 's> Checker<'p, 's> { }) } + /// The entry of `quick_initializers` for a declaration whose resolutions are right below + /// `stack[to]`. + pub(super) fn resolutions_below(&self, to: usize) -> (usize, usize) { + let mut below = self.stack[..to].iter(); + let from = below + .rposition(|&q| !self.is_resolution(q)) + .map_or(0, |i| i + 1); + (from, to) + } + /// The depth of `stack` when the top of `flowLoopStack` was pushed, if that was after /// `stack[since]` was entered. Or else when `isExhaustiveSwitchStatement` set the innermost /// `ExhaustiveStateComputing`: it goes on with an empty `flowLoopStack` @@ -1540,9 +1729,6 @@ impl<'p, 's> Checker<'p, 's> { /// parentheses around it: `e` is `reference?.a.b`, so if it has a value, so has the reference. fn optional_chain_contains(&mut self, reference: &Reference, e: ExprId) -> bool { let hir = self.hir(reference.file); - // `matches_prefix` resolves the key names itself for a reference with a path. Nearly all - // callers in flow.go test `strictNullChecks` first. - let names_keys = reference.path.is_empty() && self.p.files.options.strict_null_checks; let mut source = e; // `IsOptionalChain`: the parser gives `x!` `NodeFlagsOptionalChain` when it finds a link // without `?.` after it (`tryReparseOptionalChain`). @@ -1559,19 +1745,6 @@ impl<'p, 's> Checker<'p, 's> { if chain == Chain::No { return false; } - // `isMatchingReference` has the link as its source: `getAccessedPropertyName` resolves - // the key name of an element access before the target is inspected. - if names_keys && !matches!(hir[source].kind, ExprKind::NonNull(_)) { - let mut link = expression; - while let ExprKind::NonNull(x) | ExprKind::Satisfies { expr: x, .. } = - hir[link].kind - { - link = x; - } - if let ExprKind::Index { index, .. } = hir[link].kind { - self.literal_key(reference.file, index); - } - } if self.matches_prefix(reference, reference.path.len(), expression, true) { return true; } @@ -1708,7 +1881,11 @@ impl<'p, 's> Checker<'p, 's> { PatParent::Prop(of, prop) if of == target && hir[prop].default.is_none() && !hir[prop].is_rest => { - plain(self.literal_property_name_text(file, hir[prop].key)?) + plain(self.literal_property_name_text( + file, + hir[prop].key, + hir[prop].key_pos, + )?) } PatParent::Elem(of, elem) if of == target && hir[elem].default.is_none() && !hir[elem].is_rest => @@ -1778,7 +1955,7 @@ impl<'p, 's> Checker<'p, 's> { match (parent, hir[of].kind) { (PatParent::Prop(_, prop), _) => { let name = binding_element_property_name(hir, prop); - plain(self.literal_property_name_text(file, name)?) + plain(self.literal_property_name_text(file, name, hir[prop].key_pos)?) } (PatParent::Elem(_, elem), PatKind::Array(elems)) => { plain(self.number_name((elem.0 - elems.start) as f64)) @@ -1790,15 +1967,35 @@ impl<'p, 's> Checker<'p, 's> { } } - /// `getLiteralPropertyNameText` - fn literal_property_name_text(&mut self, file: FileId, name: PropKey) -> Option { - if let PropKey::Private(_) = name { - return None; - } - let text = self.member_name(file, name)?; + /// `getLiteralPropertyNameText` of the name `name` at `pos`. + fn literal_property_name_text( + &mut self, + file: FileId, + name: PropKey, + pos: u32, + ) -> Option { + let text = self.try_get_name_from_property_name(file, name, pos)?; (!self.atoms().is_symbol_name(text)).then_some(text) } + /// `tryGetNameFromType` of `getLiteralTypeFromPropertyName` of the name `name` at `pos`. + pub(super) fn try_get_name_from_property_name( + &mut self, + file: FileId, + name: PropKey, + pos: u32, + ) -> Option { + match name { + PropKey::Private(_) => None, + PropKey::None => { + let kind = NameKind::Identifier; + let ty = self.literal_type_from_property_name(file, name, kind, pos)?; + self.property_name_of_type(ty) + } + _ => self.member_name(file, name), + } + } + /// `isSomeSymbolAssignedWorker` fn any_binding_assigned(&self, file: FileId, pat: PatId) -> bool { let hir = self.hir(file); @@ -1867,25 +2064,27 @@ impl<'p, 's> Checker<'p, 's> { let is_constant_root = match reference.root { Root::This => true, Root::Symbol(s) => self.is_constant_name(file, s), - // A constant of another script or of the library. - Root::Global(name) => self - .files() - .global(name, SymFlags::VALUE) - .is_some_and(|sym| self.files().flags(sym).contains(SymFlags::CONST)), + Root::Global(name) => self.is_global_constant(name), Root::Pattern(p) => self.is_constant_pattern(file, p), - Root::Super | Root::ImportMeta | Root::NewTarget | Root::Params(_) | Root::Other => { + Root::Super | Root::ImportMeta | Root::NewTarget(_) | Root::Params(_) | Root::Other => { false } }; - if !is_constant_root || reference.path.contains(&Atom::NONE) { + let steps = (0..reference.path.len()).rev(); + if !is_constant_root + || (steps.clone()).any(|step| self.name_of_step(reference, step).is_none()) + { return false; } // `a.b.c`: neither the `b` of `a` nor the `c` of that can be assigned. let mut at = reference.at; - for &name in reference.path.iter().rev() { + for step in steps { let (ExprKind::Dot { obj, .. } | ExprKind::Index { obj, .. }) = hir[at].kind else { return false; }; + let Some(name) = self.name_of_step(reference, step) else { + return false; + }; let object = self.type_of_expr(file, obj); let object = self.non_nullable(object); let object = self.apparent_type(object); @@ -2009,15 +2208,14 @@ impl<'p, 's> Checker<'p, 's> { self.in_check_identifier.push((file, parent)); let flow = bound.expr_flow[e.idx()]; let ty = 'checked: { - let parent_ty = self.type_of_pat(file, parent); + let parent_ty = self.type_for_binding_element_parent(file, pat, parent); let parent_ty = self.map_type(parent_ty, Self::base_constraint_or_type); - if !self.is_union(parent_ty) - || is_parameter && self.any_binding_assigned(file, root) - || flow == UNREACHABLE - { + if !self.is_union(parent_ty) || is_parameter && self.any_binding_assigned(file, root) { break 'checked declared; } - let reference = Reference::synthetic(file, Root::Pattern(parent), SmallVec::new()); + let node = hir.node(parent); + let reference = + Reference::synthetic(file, Root::Pattern(parent), SmallVec::new(), node); let walk = Walk::new(reference, parent_ty, parent_ty, true); let narrowed = self.get_flow_type_of_reference(walk, flow); if narrowed.is_never() { @@ -2086,11 +2284,11 @@ impl<'p, 's> Checker<'p, 's> { if !self.is_union(rest_ty) || !self.every_type(rest_ty, |c, m| c.is_tuple(m)) || (params.iter()).any(|q| self.any_binding_assigned(file, hir[q].pat)) - || flow == UNREACHABLE { return declared; } - let reference = Reference::synthetic(file, Root::Params(func), SmallVec::new()); + let (root, node) = (Root::Params(func), hir.node(func)); + let reference = Reference::synthetic(file, root, SmallVec::new(), node); let walk = Walk::new(reference, rest_ty, rest_ty, true); let narrowed = self.get_flow_type_of_reference(walk, flow); // This is the result whether or not anything was narrowed: a parameter declared `x?` does @@ -2349,7 +2547,8 @@ impl<'p, 's> Checker<'p, 's> { /// assigned. fn is_test_about(&mut self, reference: &Reference, flow: FlowId, expr: ExprId) -> bool { let file = reference.file; - if self.has_order_dependent_assignment_marks(file) { + // Every comparison asks for the name of the outermost key of the reference. + if reference.unresolved.get() != 0 || self.has_order_dependent_assignment_marks(file) { return true; } let memo = &self.flow_memo; @@ -2683,7 +2882,7 @@ impl<'p, 's> Checker<'p, 's> { return result; } } - self.narrow_by_truthiness(reference, ty, e, sense) + self.narrow_by_truthiness(reference, ty, e, false, sense) } ExprKind::Call(_) => self.narrow_by_call(reference, ty, e, sense), ExprKind::NonNull(x) | ExprKind::Satisfies { expr: x, .. } => { @@ -2696,7 +2895,8 @@ impl<'p, 's> Checker<'p, 's> { ExprKind::Assign { op, target, value } => match op { None | Some(BinOp::Or | BinOp::And | BinOp::Nullish) => { let ty = self.narrow(reference, ty, value, sense); - self.narrow_by_truthiness(reference, ty, target, sense) + let in_parentheses = is_parenthesized(hir, target); + self.narrow_by_truthiness(reference, ty, target, in_parentheses, sense) } _ => ty, }, @@ -2751,26 +2951,38 @@ impl<'p, 's> Checker<'p, 's> { if self.matches(reference, e) { return self.adjusted_type_with_facts(ty, include); } + // `narrowType` passes the operand as it is written: in parentheses it is no access. + if is_parenthesized(self.hir(reference.file), e) { + return ty; + } if let Some(name) = self.discriminant_access(reference, e, ty) { return self.narrow_by_discriminant(ty, name, |c, t| c.type_with_facts(t, include)); } ty } - /// `narrowTypeByTruthiness` + /// `narrowTypeByTruthiness`. `in_parentheses`: of the `ParenthesizedExpression` around `e`, + /// which is neither an optional chain nor an access. fn narrow_by_truthiness( &mut self, reference: &Reference, ty: TypeId, e: ExprId, + in_parentheses: bool, sense: bool, ) -> TypeId { let include = if sense { facts::TRUTHY } else { facts::FALSY }; if self.matches(reference, e) { return self.adjusted_type_with_facts(ty, include); } + if in_parentheses { + return ty; + } let mut ty = ty; - if sense && self.optional_chain_contains(reference, e) { + if self.p.files.options.strict_null_checks + && sense + && self.optional_chain_contains(reference, e) + { ty = self.non_nullable(ty); } if let Some(name) = self.discriminant_access(reference, e, ty) { @@ -3284,7 +3496,8 @@ impl<'p, 's> Checker<'p, 's> { let operand = self.reference_candidate(reference.file, operand); if !self.matches(reference, operand) { let mut ty = ty; - if self.optional_chain_contains(reference, operand) + if self.p.files.options.strict_null_checks + && self.optional_chain_contains(reference, operand) && sense == (name != known::undefined) { ty = self.non_nullable(ty); @@ -3365,7 +3578,10 @@ impl<'p, 's> Checker<'p, 's> { let file = reference.file; let left = self.reference_candidate(file, left); if !self.matches(reference, left) { - if sense && self.optional_chain_contains(reference, left) { + if sense + && self.p.files.options.strict_null_checks + && self.optional_chain_contains(reference, left) + { return self.non_nullable(ty); } return ty; @@ -3646,13 +3862,14 @@ impl<'p, 's> Checker<'p, 's> { } // `"a" in x` narrows `x.a` by presence if its type includes the missing type // (`containsMissingType`). - if let Some((&last, _)) = reference.path.split_last() - && reference.accesses != 0 + if reference.accesses != 0 && self.contains_missing_type(ty) && self.matches_prefix(reference, reference.path.len() - 1, right, false) { let key = self.get_type_of_expression(file, left); - if self.property_name_of_type(key) == Some(last) { + if let Some(key) = self.property_name_of_type(key) + && self.name_of_step(reference, reference.path.len() - 1) == Some(key) + { return self.type_with_facts( ty, if sense { @@ -3728,8 +3945,7 @@ impl<'p, 's> Checker<'p, 's> { // `x.hasOwnProperty("a")` narrows `x.a` like `"a" in x`. let file = reference.file; let hir = self.hir(file); - if let Some((&last, _)) = reference.path.split_last() - && reference.accesses != 0 + if reference.accesses != 0 && self.contains_missing_type(ty) && let ExprKind::Call(c) = hir[call].kind && let ExprKind::Dot { obj, name, .. } = hir[hir[c].callee].kind @@ -3739,6 +3955,7 @@ impl<'p, 's> Checker<'p, 's> { if self.matches_prefix(reference, reference.path.len() - 1, obj, false) && self.atoms().bytes(name) == b"hasOwnProperty" && hir[c].args.len() == 1 + && let Some(last) = self.name_of_step(reference, reference.path.len() - 1) && let ExprKind::String(text) = hir[hir.id_at(hir[c].args, 0)].kind && !is_parenthesized(hir, hir.id_at(hir[c].args, 0)) && text == last @@ -4378,6 +4595,9 @@ impl<'p, 's> Checker<'p, 's> { { return declared; } + if let Some(frame) = self.frames.last_mut() { + frame.may_substitute_constraints = true; + } if !self.is_constraint_position(file, e, declared) { // `hasContextualTypeWithNoGenericTypes` let context_flags = if check_mode.contains(CheckMode::REST_BINDING_ELEMENT) { @@ -4450,8 +4670,13 @@ impl<'p, 's> Checker<'p, 's> { ty } - /// `getFlowTypeOfReference` of a `this` expression (`tryGetThisTypeAtEx`). - pub(super) fn narrow_this(&mut self, file: FileId, e: ExprId, declared: TypeId) -> TypeId { + /// `getFlowTypeOfReference(e, declared)` + pub(super) fn flow_type_of_reference( + &mut self, + file: FileId, + e: ExprId, + declared: TypeId, + ) -> TypeId { if declared == TypeId::UNRESOLVED || declared.is_never() { return declared; } @@ -4594,16 +4819,19 @@ impl<'p, 's> Checker<'p, 's> { && container_of(e) == container_of(assignment) } - /// The type of `e`, the initializer of a variable or a parameter declared by a binding pattern - /// without a type annotation, for the `...rest` of the pattern - /// (`CheckModeRestBindingElement`). `None`: the same type the other elements see. - pub(super) fn type_of_reference_for_rest(&mut self, file: FileId, e: ExprId) -> Option { - let ordinary = self.type_of_expr(file, e); - if self.is_any(ordinary) { - return None; + /// `checkDeclarationInitializer(declaration, CheckModeRestBindingElement, nil)`, before it pads + /// the type: `e` is the initializer of a variable or a parameter declared by a binding pattern + /// without a type annotation, and the type is for the `...rest` of the pattern. Under that mode + /// `checkExpressionCachedEx` assigns no `links.resolvedType` and leaves `flowLoopStack` as it is. + pub(super) fn check_declaration_initializer_for_rest( + &mut self, + file: FileId, + e: ExprId, + ) -> TypeId { + match self.quick_type_of_expr(file, e) { + Some(quick) => quick, + None => self.check_expression_cached_ex(file, e, CheckMode::REST_BINDING_ELEMENT), } - let ty = self.check_expression_cached_ex(file, e, CheckMode::REST_BINDING_ELEMENT); - (ty != ordinary).then_some(ty) } /// Whether `e` is the `x` of `x!`. Not of `(x)!`: only the direct syntactic parent counts. @@ -4658,14 +4886,32 @@ impl<'p, 's> Checker<'p, 's> { /// `FindAncestor(e, IsFunctionOrModuleBlock)` pub(super) fn function_or_module_block_of(&self, file: FileId, e: ExprId) -> Node { + self.function_or_module_block_of_node(file, self.hir(file).node(e)) + } + + /// `FindAncestor(node, IsFunctionOrModuleBlock)` + fn function_or_module_block_of_node(&self, file: FileId, node: Node) -> Node { let hir = self.hir(file); - hir.find_ancestor(hir.node(e), |n| match hir.kind(n) { + hir.find_ancestor(node, |n| match hir.kind(n) { Kind::SourceFile | Kind::ModuleBlock => true, Kind::Block => hir.kind(hir.parent(n)).is_function_like(), _ => false, }) } + /// `reportFlowControlError(f.reference)`. `check_flow_too_deep` reports 2563 from the tables. + fn report_flow_control_error(&self, reference: &Reference) { + let file = reference.file; + match reference.at.some() { + Some(e) => (self.p.flows_too_deep).insert(&self.task, (file, e), (), Stored::new()), + None => { + let block = self.function_or_module_block_of_node(file, reference.node); + let blocks = &self.p.blocks_too_large_for_flow_analysis; + blocks.insert(&self.task, (file, block), (), Stored::new()); + } + } + } + /// Not in tsgo. The symbols of `file` that some node of its flow graph refers to: a condition /// (`note_test`, as for `is_test_about`), a `switch`, an assignment target, the expression of a /// `for in`. Nothing else can change the type of a reference rooted at a name, except an @@ -5116,6 +5362,7 @@ impl<'p, 's> Checker<'p, 's> { ) -> bool { let file = reference.file; if !matches!(reference.root, Root::Symbol(_) | Root::Other) + || reference.unresolved.get() != 0 || self.task.file != Some(file) || self.is_automatic_type(declared) // See `NarrowingSubjects::add_union`. @@ -5131,7 +5378,9 @@ impl<'p, 's> Checker<'p, 's> { let memo = &self.flow_memo; let flow = bound.expr_flow[e.idx()]; // Nothing matches `f()["a"]` or `a[i]`, and an assignment to `a` leaves `a[i]` as declared. - if reference.root == Root::Other || reference.path.last() == Some(&Atom::NONE) { + let matches_nothing = + |step: &Step| step.name.get() == AccessedName::None && step.variable == Root::Other; + if reference.root == Root::Other || reference.path.last().is_some_and(matches_nothing) { return start == Start::Known && !memo.first_narrowing_node.is_empty() && !self.may_resolve_key(reference, e, memo.max_antecedent[flow.idx()]) @@ -5339,9 +5588,7 @@ impl<'p, 's> Checker<'p, 's> { // errorType, and `reportFlowControlError` if walk.too_deep { self.flow_analysis_disabled = true; - if e.is_some() { - (self.p.flows_too_deep).insert(&self.task, (file, e), (), Stored::new()); - } + self.report_flow_control_error(&walk.reference); return TypeId::ERROR; } if walk.steps >= MAX_STEPS { @@ -5387,7 +5634,7 @@ impl<'p, 's> Checker<'p, 's> { let name = match bound.pat_parent[at.idx()] { PatParent::Prop(parent, p) if !hir[p].is_rest => { at = parent; - self.literal_property_name_text(file, hir[p].key) + self.literal_property_name_text(file, hir[p].key, hir[p].key_pos) } PatParent::Elem(parent, e) if !hir[e].is_rest => { let PatKind::Array(elems) = hir[parent].kind else { @@ -5427,7 +5674,7 @@ impl<'p, 's> Checker<'p, 's> { let name = match bound.expr_parent[at.idx()] { Parent::Prop(p) if hir[p].kind != PropKind::Spread => { at = bound.prop_owner[p.idx()]; - self.literal_property_name_text(file, hir[p].key) + self.literal_property_name_text(file, hir[p].key, hir[p].pos) } Parent::Expr(x) => match hir[x].kind { ExprKind::Array(items) => { @@ -5477,21 +5724,23 @@ impl<'p, 's> Checker<'p, 's> { return declared; } let mut reference = self.reference_of(file, init); - reference.path.extend(names.iter().rev().copied()); + let steps = names.iter().rev().map(|&name| Step::named(name)); + reference.path.extend(steps); reference.accesses += names.len(); - // It does not occur in the source. - reference.at = ExprId::NONE; + // It does not occur in the source. Its parent is in the declaration or the assignment that + // `init` is in. + (reference.at, reference.node) = (ExprId::NONE, self.hir(file).node(init)); let walk = Walk::new(reference, declared, declared, false); self.get_flow_type_of_reference(walk, flow) } - /// Whether `this.name`, declared as `declared`, has been assigned by the end of the constructor - /// `func`. + /// Whether `this.name` or `this[k]`, declared as `declared`, has been assigned by the end of the + /// constructor `func`. pub(super) fn is_assigned_in_constructor( &mut self, file: FileId, func: FnId, - name: Atom, + key: AccessKey, declared: TypeId, ) -> bool { let exit = self.bound(file).fns[func.idx()].exit; @@ -5502,7 +5751,15 @@ impl<'p, 's> Checker<'p, 's> { return true; } let initial = self.optional(declared); - let reference = Reference::synthetic(file, Root::This, smallvec![name]); + let path = smallvec![match key { + AccessKey::Name(name) => Step::named(name), + AccessKey::Variable(variable) => Step { + name: std::cell::Cell::new(AccessedName::None), + variable, + }, + }]; + let constructor = self.hir(file).node(func); + let reference = Reference::synthetic(file, Root::This, path, constructor); let walk = Walk::new(reference, declared, initial, false); let ty = self.get_flow_type_of_reference(walk, exit); !self.contains_undefined(ty) @@ -5526,7 +5783,8 @@ impl<'p, 's> Checker<'p, 's> { if exit.is_none() { return None; } - let reference = Reference::synthetic(file, Root::This, smallvec![name]); + let (path, parent) = (smallvec![Step::named(name)], self.hir(file).node(func)); + let reference = Reference::synthetic(file, Root::This, path, parent); let walk = Walk::new(reference, TypeId::AUTO, initial, false); let ty = self.get_flow_type_of_reference(walk, exit); if self.p.files.options.no_implicit_any && self.is_automatic_type(ty) { @@ -5590,6 +5848,7 @@ impl<'p, 's> Checker<'p, 's> { /// made for the symbol. If it finds `x++` or `x += 1` only, `hasDefiniteAssignment` stays /// unset. That is read for a `let` without an initializer. /// - A function below a node that no walk enters is walked if none around it has the flag yet. + /// - Only a walk resolves the `unchecked_assignment_targets`, so which walks are made shows. #[inline] pub(super) fn has_order_dependent_assignment_marks(&self, file: FileId) -> bool { let is_possible = match self.flow_memo.latest_order_dependent_assignment_marks.get() { @@ -5651,6 +5910,9 @@ impl<'p, 's> Checker<'p, 's> { /// `has_order_dependent_assignment_marks`, from the assignments of `file`. fn is_some_assignment_marked_in_order(&self, file: FileId) -> bool { let (hir, bound) = (self.hir(file), self.bound(file)); + if !bound.unchecked_assignment_targets.is_empty() { + return true; + } if bound.assignments.is_empty() { return false; } @@ -5793,6 +6055,23 @@ impl<'p, 's> Checker<'p, 's> { is_marked.then_some(referencing_function != declaring_function) } + /// `markNodeAssignmentsWorker`: `getResolvedSymbol(node)`, with its errors, for the assignment + /// targets of `file` that nothing else resolves and that a walk has got to. + pub(super) fn resolve_marked_assignment_targets(&mut self, file: FileId) { + let (hir, bound) = (self.hir(file), self.bound(file)); + for &target in bound.unchecked_assignment_targets.iter() { + let ExprKind::Ident(name) = hir[target].kind else { + continue; + }; + let node = hir.node(target); + if bound.get_assignment_target_kind(hir, target) != AssignmentKind::None + && (self.is_marked_in_nested_function(file, Node::NONE, node)).is_some() + { + self.resolve_unchecked_assignment_target(file, target, name); + } + } + } + /// `isSymbolAssignedDefinitely`. `+=` and `++` modify a value, they do not initialize one. pub(super) fn is_symbol_assigned_definitely(&self, file: FileId, symbol: SymbolId) -> bool { self.ensure_assignments_marked(file, symbol); @@ -5997,18 +6276,20 @@ impl<'p, 's> Checker<'p, 's> { } } - /// `getContextFreeTypeOfExpression`. tsgo caches every result. One that depends on an incomplete loop type is cached here for the - /// traversal of the back edge only, like `flowTypeCache`. + /// `getContextFreeTypeOfExpression`. tsgo keeps the first result, also one that depends on the + /// incomplete type of a loop in progress: `FlowMemo::context_free_types_in_loops`. fn context_free_type_of_expression(&mut self, file: FileId, e: ExprId) -> TypeId { if let Some(kept) = self.p.context_free_expr_types.get(&self.task, &(file, e)) { return kept; } + let in_loops = &self.flow_memo.context_free_types_in_loops; + if !in_loops.is_empty() + && let Some(&kept) = in_loops.get(&(file, e)) + { + return kept; + } let depth = self.flow_type_cache_depth; let is_in_back_edge = depth != usize::MAX && self.is_flow_loop_visible(depth); - if is_in_back_edge && let Some(&cached) = self.flow_type_cache.get(&(file, e, true)) { - self.taint_from(depth); - return cached; - } let level = self.inference_contexts.len() + 1; let outer = std::mem::replace(&mut self.context_free_level, level); let (ty, stored) = self.run_memoizable(|c| { @@ -6020,8 +6301,9 @@ impl<'p, 's> Checker<'p, 's> { && !self.is_stack_low() { (self.p.context_free_expr_types).rewrite(&self.task, (file, e), ty, stored); - } else if is_in_back_edge { - self.flow_type_cache.insert((file, e, true), ty); + } else if is_in_back_edge && ty != TypeId::UNRESOLVED { + let in_loops = &mut self.flow_memo.context_free_types_in_loops; + in_loops.insert((file, e), ty); } ty } @@ -6110,7 +6392,7 @@ impl<'p, 's> Checker<'p, 's> { // Never walked without a path, or walked with `crosses_functions`. Root::Super | Root::ImportMeta - | Root::NewTarget + | Root::NewTarget(_) | Root::Pattern(_) | Root::Params(_) | Root::Other => false, @@ -6264,12 +6546,20 @@ impl<'p, 's> Checker<'p, 's> { } // `getTypeAtFlowLoopLabel`: a reference without a key has its declared type at // a loop label. - if !self.has_flow_reference_key(&walk.reference) { + let has_key = match walk.has_reference_key { + Some(has_key) => has_key, + None => { + let has_key = self.has_flow_reference_key(&walk.reference); + if has_key && self.hands_out_symbol_ids() { + self.get_symbol_ids_of_flow_reference(&walk.reference); + } + walk.has_reference_key = Some(has_key); + has_key + } + }; + if !has_key { break walk.declared; } - if self.hands_out_symbol_ids() { - self.get_symbol_ids_of_flow_reference(&walk.reference); - } let initial = self.initial_of(walk); let key = (file, flow, walk.declared, initial); if let Some(cached) = @@ -6532,6 +6822,13 @@ impl<'p, 's> Checker<'p, 's> { && reference.accesses == reference.path.len() && reference.assigned == usize::MAX }; + // Both ask for the name of each access before they look at a declaration. + if reference.unresolved.get() != 0 && !matches!(target, FlowTarget::Expr(_)) { + let len = reference.path.len(); + for step in (len - reference.accesses..len).rev() { + self.name_of_step(reference, step); + } + } // `isMatchingReference(f.reference, node)`, or else `containsMatchingReference(f.reference, node)` let is_matching = match target { FlowTarget::Var(d) if declares(hir[d].pat) => reference.path.is_empty(), @@ -6616,7 +6913,7 @@ impl<'p, 's> Checker<'p, 's> { if depth == usize::MAX || !self.is_flow_loop_visible(depth) { return self.type_of_declaration_initializer(file, e); } - if let Some(&cached) = self.flow_type_cache.get(&(file, e, false)) { + if let Some(&cached) = self.flow_type_cache.get(&(file, e)) { // The entry was computed from an incomplete loop type. self.taint_from(depth); return cached; @@ -6624,7 +6921,7 @@ impl<'p, 's> Checker<'p, 's> { let start = self.flow_invocation_count; let ty = self.type_of_declaration_initializer(file, e); if self.flow_invocation_count != start && self.cached_type_of_expr(file, e).is_none() { - self.flow_type_cache.insert((file, e, false), ty); + self.flow_type_cache.insert((file, e), ty); } ty } @@ -6689,8 +6986,9 @@ impl<'p, 's> Checker<'p, 's> { PatParent::Prop(pattern, prop) => { let parent_type = self.get_initial_type(file, pattern); let name = binding_element_property_name(hir, prop); + let pos = hir[prop].key_pos; ( - self.get_type_of_destructured_property(file, parent_type, name), + self.get_type_of_destructured_property(file, parent_type, name, pos), hir[prop].default, ) } @@ -6803,7 +7101,7 @@ impl<'p, 's> Checker<'p, 's> { { return element_type; } - let element_type = self.iterated_type_of_destructuring(ty); + let element_type = self.iterated_type_of_destructuring_in_flow(ty); self.include_undefined_in_index_signature(element_type) } @@ -6858,7 +7156,7 @@ impl<'p, 's> Checker<'p, 's> { /// `getTypeOfDestructuredSpreadExpression` fn get_type_of_destructured_spread_expression(&mut self, ty: TypeId) -> TypeId { - let element_type = self.iterated_type_of_destructuring(ty); + let element_type = self.iterated_type_of_destructuring_in_flow(ty); self.array_of(element_type) } @@ -6866,22 +7164,19 @@ impl<'p, 's> Checker<'p, 's> { fn get_assigned_type_of_property_assignment(&mut self, file: FileId, prop: PropId) -> TypeId { let owner = self.bound(file).prop_owner[prop.idx()]; let ty = self.get_assigned_type(file, owner, false); - self.get_type_of_destructured_property(file, ty, self.hir(file)[prop].key) + let written = &self.hir(file)[prop]; + self.get_type_of_destructured_property(file, ty, written.key, written.pos) } - /// `getTypeOfDestructuredProperty` + /// `getTypeOfDestructuredProperty`, for the name `name` at `pos`. fn get_type_of_destructured_property( &mut self, file: FileId, ty: TypeId, name: PropKey, + pos: u32, ) -> TypeId { - // `getLiteralTypeFromPropertyName` of a private name is `never`. - let text = match name { - PropKey::Private(_) => None, - _ => self.member_name(file, name), - }; - let Some(text) = text else { + let Some(text) = self.try_get_name_from_property_name(file, name, pos) else { return TypeId::ERROR; }; if let Some(prop_type) = self.type_of_property_of_type(ty, text) { @@ -7862,7 +8157,8 @@ impl<'p, 's> Checker<'p, 's> { continue; } // `checkIfExpressionRefinesParameter` - let reference = Reference::synthetic(file, Root::Symbol(symbol), SmallVec::new()); + let (root, node) = (Root::Symbol(symbol), hir.node(param.pat)); + let reference = Reference::synthetic(file, root, SmallVec::new(), node); let outer = std::mem::replace(&mut self.walk_declared, declared); let when_true = self.param_type_past_test(&reference, declared, declared, before, body, true); @@ -7905,13 +8201,17 @@ impl<'p, 's> Checker<'p, 's> { if self.flow_analysis_disabled { return TypeId::ERROR; } + self.flow_invocation_count += 1; let start = if before.is_none() { initial } else { let mut walk = Walk::new(reference.clone(), declared, initial, false); + // The invocation of `getTypeAtFlowNode` for the synthesized condition is in progress. + walk.depth = 1; let ty = self.flow_type(&mut walk, before).ty; if walk.too_deep { self.flow_analysis_disabled = true; + self.report_flow_control_error(reference); return TypeId::ERROR; } if walk.steps >= MAX_STEPS { diff --git a/src/sema/check/grammarchecks.rs b/src/sema/check/grammarchecks.rs index 70b45bcc54a5..437ca7627b35 100644 --- a/src/sema/check/grammarchecks.rs +++ b/src/sema/check/grammarchecks.rs @@ -179,23 +179,26 @@ impl Checker<'_, '_> { || self.check_grammar_for_use_strict_simple_parameter_list(file, func) } - /// `checkGrammarTypeParameterList`: `<>`. Before an arrow function the parser rejects it. + /// `checkGrammarTypeParameterList`: `<>`. Before an arrow function the parser rejects it. The + /// list is not stored: it is what precedes `anchor`, the token at which `parseParameters` + /// starts, a `(` or not. A signature that the reparser makes of JSDoc tags has none. fn check_grammar_type_parameter_list(&mut self, file: FileId, func: FnId) -> bool { let hir = self.hir(file); let (text, f) = (&hir.text[..], &hir[func]); - if !f.type_params.is_empty() - || f.kind == FnKind::Arrow - || text.get(f.anchor as usize) != Some(&b'(') + if !f.type_params.is_empty() || f.kind == FnKind::Arrow || f.flags.contains(Flags::REPARSED) { return false; } - let close = skip_trivia_back(text, f.anchor as usize); + let close = skip_trivia_back(text, hir.skip_trivia_of_node_at(f.anchor) as usize); if !text[..close].ends_with(b">") { return false; } - let open = skip_trivia_back(text, close - 1); - text[..open].ends_with(b"<") - && self.grammar_error_at((file, open as u32 - 1, close as u32), 1098, &[]) + // `typeParameters.Pos()`, which is its `End()`. + let greater_than = hir.skip_trivia_of_node_at(close as u32 - 1); + let pos = skip_trivia_back(text, greater_than as usize); + let end = skip_trivia(text, pos) + 1; + text[..pos].ends_with(b"<") + && self.grammar_error_at((file, pos as u32 - 1, end as u32), 1098, &[]) } /// `checkGrammarParameterList` @@ -771,9 +774,7 @@ impl Checker<'_, '_> { // A name that declares nothing (`getDeclarationName`) is not stored. PropKey::None if is_private_name_at(hir, pos) => self.declaration_name_at(file, pos), PropKey::None if is_bigint_literal_at(hir, pos) => { - let mut text = self.declaration_name_at(file, pos); - text.retain(|&digit| digit != b'_'); - text + crate::json::bigint_token_value(&self.declaration_name_at(file, pos)) } PropKey::None => return None, }; diff --git a/src/sema/check/infer.rs b/src/sema/check/infer.rs index cbfdbbc64682..056578f04a4b 100644 --- a/src/sema/check/infer.rs +++ b/src/sema/check/infer.rs @@ -78,8 +78,6 @@ pub(super) struct Inference { calls: u32, /// The parameter type an inference started from. original_target: TypeId, - /// The source is the type implied by a binding pattern (`patternForType`). - pub(super) from_pattern: bool, /// `InferenceFlagsAnyDefault`: the call is in a JavaScript file, where a parameter without /// inferences is `any`. pub(super) any_default: bool, @@ -133,7 +131,6 @@ impl Inference { depth: 0, calls: 0, original_target: TypeId::NEVER, - from_pattern: false, any_default: false, around_source: MapperId::IDENTITY, around: MapperId::IDENTITY, @@ -1783,6 +1780,11 @@ impl<'p, 's> Checker<'p, 's> { Some(last) if last.rest => usize::MAX, _ => tp.len(), }; + // `getParameterCount(source)`, then `getThisTypeOfSignature`, then `getTypeAtPosition`. + self.request_type_of_rest_parameter(source); + let this_types = self + .sig_this_type(source) + .and_then(|s| self.sig_this_type(target).map(|t| (s, t))); let sp = self.sig_params_up_to(source, requested); let (source_count, target_count) = (self.parameter_count(&sp), self.parameter_count(&tp)); let (source_rest, target_rest) = @@ -1800,11 +1802,7 @@ impl<'p, 's> Checker<'p, 's> { // `getTypeAtPosition(target, i)` self.note_parameter_types_resolved(target, &tp, param_count); let mut pairs: SmallVec<[(TypeId, TypeId); 8]> = SmallVec::with_capacity(param_count + 2); - if let Some(s) = self.sig_this_type(source) - && let Some(t) = self.sig_this_type(target) - { - pairs.push((s, t)); - } + pairs.extend(this_types); for i in 0..param_count { let (s, t) = ( self.param_type_at(&sp, i).unwrap_or(TypeId::ANY), @@ -1971,13 +1969,7 @@ impl<'p, 's> Checker<'p, 's> { let keys = match self.data(source) { // `patternForType`, `IndexFlagsNoIndexSignatures`: the `...rest` of a pattern // is not a key. - TypeData::Synth(shape) - if n.from_pattern - || matches!( - shape.literal, - Literalness::Pattern | Literalness::PatternWithComputedNames - ) => - { + TypeData::Synth(shape) if shape.literal.is_of_pattern() => { let mut keys = Vec::with_capacity(shape.props.len()); for prop in &shape.props { keys.extend(self.key_type_of_name(prop.name)); @@ -2868,7 +2860,7 @@ impl<'p, 's> Checker<'p, 's> { compare: &mut dyn FnMut(&mut Self, TypeId, TypeId) -> bool, ) -> MapperId { if !self.has_type_variables(ty) { - return MapperId::IDENTITY; + return self.mapper_of_context_not_mentioned_in(ty); } let mut pairs = Vec::new(); let mentioned = self.params_mentioned_in(ty, &n.params); @@ -2879,15 +2871,28 @@ impl<'p, 's> Checker<'p, 's> { } } if pairs.is_empty() { - return MapperId::IDENTITY; + return self.mapper_of_context_not_mentioned_in(ty); } self.types().mapper(pairs) } + /// The mapper of an inference context, for a `ty` that mentions none of its type parameters. + /// It is not nil, so `instantiateType` replaces what has + /// `ObjectFlags::HAS_OTHER_INSTANTIATION`. Only a type parameter is looked up in a mapper: the + /// pair maps nothing. + fn mapper_of_context_not_mentioned_in(&self, ty: TypeId) -> MapperId { + let flags = self.types().object_flags(ty); + if flags.contains(ObjectFlags::HAS_OTHER_INSTANTIATION) { + self.types().mapper_of(&[(TypeId::NEVER, TypeId::UNKNOWN)]) + } else { + MapperId::IDENTITY + } + } + /// `context.mapper`, for what `ty` mentions (`InferenceTypeMapper.Map`). pub(super) fn fixing_mapper(&mut self, n: &mut Inference, ty: TypeId) -> MapperId { if !self.may_mention_type_parameter(ty) { - return MapperId::IDENTITY; + return self.mapper_of_context_not_mentioned_in(ty); } let mentioned = self.params_mentioned_in(ty, &n.params); let mut pairs = Vec::new(); @@ -2903,7 +2908,7 @@ impl<'p, 's> Checker<'p, 's> { pairs.push((n.params[i], self.get_inferred_type(n, i, true))); } if pairs.is_empty() { - return MapperId::IDENTITY; + return self.mapper_of_context_not_mentioned_in(ty); } self.types().mapper(pairs) } @@ -2991,10 +2996,10 @@ impl<'p, 's> Checker<'p, 's> { MapperId::IDENTITY, self.flags(ty) & tf::ENUM_LITERAL == 0 && some(types), ), - // Not exact: a `Synth` does not say that it is a rest type (`ObjectFlagsObjectRestType`). TypeData::Synth(shape) => ( shape.mapper, - shape.instantiation_expression.is_some() + shape.is_object_rest_type + || shape.instantiation_expression.is_some() || shape.symbol_declared_at.is_some_and(|it| it.2.is_some()), ), _ => return false, @@ -3010,9 +3015,12 @@ impl<'p, 's> Checker<'p, 's> { /// `isNonGenericTopLevelType` fn is_non_generic_top_level_type(&self, ty: TypeId) -> bool { - let Some(alias) = self.alias_symbol_of_type(ty) else { - return false; - }; + self.alias_symbol_of_type(ty) + .is_some_and(|alias| self.is_non_generic_top_level_alias(alias)) + } + + /// The same for a type whose `alias.symbol` is `alias`. + pub(super) fn is_non_generic_top_level_alias(&self, alias: Sym) -> bool { let declarations = self.files().decls_of(alias); let Some((file, declaration)) = declarations.iter().find_map(|&(file, decl)| match decl { Decl::Alias(declaration) => Some((file, declaration)), diff --git a/src/sema/check/instantiate.rs b/src/sema/check/instantiate.rs index 31c37dd4b875..16d817763c60 100644 --- a/src/sema/check/instantiate.rs +++ b/src/sema/check/instantiate.rs @@ -616,6 +616,23 @@ impl<'p, 's> Checker<'p, 's> { self.intern_key(TypeKey::Fns { decls, mapper: new }) } TypeData::Synth(shape) => { + // `getObjectTypeInstantiation` of an `InstantiationExpressionType`: `newMapper` maps + // `links.outerTypeParameters`, and `instantiateAnonymousType` instantiates the + // members of `target` with it, whatever else they mention. + let (mut shape, mut mapper, mut target) = (shape, mapper, None); + if shape.instantiation_expression.is_some() { + let new_mapper = self.map_mapper(shape.mapper, mapper); + if new_mapper == shape.mapper { + return ty; + } + let created = shape.instantiation_target.unwrap_or(ty); + if let TypeData::Synth(as_created) = self.data(created) { + if new_mapper == as_created.mapper { + return created; + } + (shape, mapper, target) = (as_created, new_mapper, Some(created)); + } + } let scope = self.begin_scope(); let mut new = Shape { literal: shape.literal, @@ -655,6 +672,7 @@ impl<'p, 's> Checker<'p, 's> { .map(|&s| self.instantiate_sig(s, mapper)), ); new.symbol_declared_at = shape.symbol_declared_at; + new.symbol = shape.symbol; new.spread_rank = shape.spread_rank; new.spread_of = shape.spread_of.map(|(left, right)| { ( @@ -664,7 +682,9 @@ impl<'p, 's> Checker<'p, 's> { }); // `instantiateAnonymousType` new.instantiation_expression = shape.instantiation_expression; + new.instantiation_target = target; new.is_js_literal = shape.is_js_literal; + new.is_object_rest_type = shape.is_object_rest_type; new.mapper = self.map_mapper(shape.mapper, mapper); let stored = self.end_scope_by_counters(scope); if let Some(arguments) = shape.single_signature_arguments { diff --git a/src/sema/check/late_bound.rs b/src/sema/check/late_bound.rs index ab865385b256..8326bca65a5a 100644 --- a/src/sema/check/late_bound.rs +++ b/src/sema/check/late_bound.rs @@ -29,6 +29,8 @@ struct LateBoundSymbol { declarations: Vec<(FileId, Decl)>, /// `symbol.ValueDeclaration` value_declaration: Option<(FileId, Decl)>, + /// `getMergedSymbol(symbol).CheckFlags&CheckFlagsLate != 0`: `cloneSymbol` does not copy it. + is_late: bool, } /// What `getResolvedMembersOrExportsOfSymbol` adds to the binder's table of one side of a container. @@ -95,7 +97,16 @@ impl<'p, 's> Checker<'p, 's> { { return None; } - let late = self.late_bound_members(files.sym(file, parent), is_static)?; + let side = (files.sym(file, parent), is_static); + let asks_by_itself = name == known::computed && matches!(declaration, Decl::Member(_)); + if asks_by_itself { + self.late_binding_by_symbol.push(side); + } + let late = self.late_bound_members(side.0, is_static); + if asks_by_itself { + self.late_binding_by_symbol.pop(); + } + let late = late?; let symbol = *late.symbol_of.get(&(file, declaration))?; Some((late, symbol as usize)) } @@ -131,6 +142,14 @@ impl<'p, 's> Checker<'p, 's> { } } + /// `EmitResolver.IsLateBound` + pub(super) fn is_late_bound(&mut self, file: FileId, m: MemberId) -> bool { + match self.late_bound_symbol(file, Decl::Member(m)) { + Some((late, symbol)) => late.symbols[symbol].is_late, + None => self.is_late_bound_by_another_call(file, m), + } + } + /// `symbol.Flags`, `symbol.ValueDeclaration` and `symbol.Declarations` of the symbol of a /// property. pub(super) fn merged_symbol_of_property( @@ -178,6 +197,27 @@ impl<'p, 's> Checker<'p, 's> { self.declarations_of_member(file, declaration) } + /// The same while `declaration` is checked. `checkIndexConstraints` has resolved the members of + /// a class or an interface before they are checked, and `checkObjectLiteral` has asked for the + /// symbol of every member. `checkTypeLiteral` checks the members first. + pub(super) fn declarations_of_symbol_of_checked_declaration( + &mut self, + file: FileId, + declaration: Decl, + ) -> List<'p, (FileId, Decl)> { + match declaration { + Decl::Member(m) + if matches!( + self.bound(file).member_owner[m.idx()], + crate::bind::MemberOwner::TypeLiteral(_) + ) => + { + self.declarations_of_symbol_of_declaration(file, declaration) + } + _ => self.declarations_of_member(file, declaration), + } + } + /// `getExportsOfSymbol(container)[name]`, where the binder's table has the alias `early`. /// `None`: the late bound symbol of that name. pub(super) fn resolved_export_of_alias( @@ -340,6 +380,7 @@ impl<'p, 's> Checker<'p, 's> { flags: SymFlags::empty(), declarations: Vec::new(), value_declaration: None, + is_late: true, }); } // `addDeclarationToLateBoundSymbol` @@ -390,6 +431,7 @@ impl<'p, 's> Checker<'p, 's> { match resolved_target { AliasTarget::Symbol(resolved) if resolved == target => { let merged = &mut late[index]; + merged.is_late = false; merged.flags |= target_flags; merged.declarations.splice(0..0, files.decls(target)); let of_target = files.value_declaration(target); @@ -399,6 +441,7 @@ impl<'p, 's> Checker<'p, 's> { } } AliasTarget::Symbol(resolved) if !is_excluded(files.flags(resolved)) => { + late[index].is_late = false; replaced_aliases.push((name, Some(resolved))); } // "return source" diff --git a/src/sema/check/mapped.rs b/src/sema/check/mapped.rs index 92f7a0d26bef..b9b40d2635c0 100644 --- a/src/sema/check/mapped.rs +++ b/src/sema/check/mapped.rs @@ -5,6 +5,7 @@ use super::related::Place; use super::*; use crate::bind::Decl; use crate::bind::Parent; +use crate::resolve::{is_cased_since_unicode_16, to_lowercase_unicode_15, to_uppercase_unicode_15}; use smallvec::SmallVec; /// `accessNode` of `getIndexedAccessTypeOrUndefined`. `None`: an access that instantiation or a constraint produces. `Other`: a name in a @@ -139,7 +140,7 @@ impl<'p, 's> Checker<'p, 's> { if mapped.name_ty.is_none() { return false; } - let declared = self.type_from_node(file, mapped.name_ty); + let declared = self.declared_name_type_of_mapped(file, node); let param = self.type_param(file, mapped.param); let with_keys = self.mapper_with_pair(mapper, param, constraint); // The name may contain `ty`: `{ [K in keyof C as C[K] & string]: 1 }` as a member of @@ -258,7 +259,7 @@ impl<'p, 's> Checker<'p, 's> { let name_type = if decl.name_ty.is_some() { Some(( self.type_param(file, decl.param), - self.type_from_node(file, decl.name_ty), + self.declared_name_type_of_mapped(file, node), )) } else { None @@ -459,13 +460,24 @@ impl<'p, 's> Checker<'p, 's> { } let text = self.atoms().bytes(prop.name); let (file, (key, name_kind)) = match &prop.source { - PropSource::Symbol(sym) - if let Some((file, Decl::Member(member))) = - self.files().value_declaration(*sym) => - { - let hir = self.hir(file); - (file, hir.key_of(hir.node(member))) - } + PropSource::Symbol(sym) => match self.files().value_declaration(*sym) { + Some((file, Decl::Member(member))) => { + let hir = self.hir(file); + (file, hir.key_of(hir.node(member))) + } + Some(( + file, + Decl::Expando(e) | Decl::ThisProperty(e) | Decl::ExportsProperty(e), + )) => { + let key = self.key_of_assignment_declaration(file, e); + (file, (key, Default::default())) + } + // An alias: `export { x as "0" }`. + None if !text.starts_with(crate::atom::SYMBOL_NAME_PREFIX) => { + return Some(self.string_literal(prop.name, false)); + } + _ => return self.key_type_of_name(prop.name), + }, PropSource::Literal(file, written) => { let written = &self.hir(*file)[*written]; (*file, (written.key, written.name_kind)) @@ -486,15 +498,36 @@ impl<'p, 's> Checker<'p, 's> { PropKey::Computed(_) => !text.starts_with(crate::atom::SYMBOL_NAME_PREFIX), _ => false, }; + // A late-bound symbol has a `nameType`, which spells its name. The name of `[+2]` is `+2`. + let is_late_bound = + matches!(key, PropKey::Computed(e) if is_dynamic_name(self.hir(file), e)); + // The position is read only for a name that is not stored. if is_by_syntax - && let Some(ty) = self.literal_type_from_property_name(file, key, name_kind) - && self.property_name_of_type(ty) == Some(prop.name) + && let Some(ty) = self.literal_type_from_property_name(file, key, name_kind, 0) + && (!is_late_bound || self.property_name_of_type(ty) == Some(prop.name)) { return Some(ty); } self.key_type_of_name(prop.name) } + /// `GetNonAssignedNameOfDeclaration` of the assignment or the call `e`, which declares a + /// property, as the name of a member: the `a` of `f.a = v`, and `[k]` for `f[k] = v` and for + /// `Object.defineProperty(f, k, d)`. A `k` that is no literal gives the symbol its `nameType`. + pub(super) fn key_of_assignment_declaration(&self, file: FileId, e: ExprId) -> PropKey { + let hir = self.hir(file); + let argument = if let ExprKind::Assign { target, .. } = hir[e].kind { + match hir[target].kind { + ExprKind::Dot { name, .. } => return PropKey::Name(name), + ExprKind::Index { index, .. } => Some(index), + _ => None, + } + } else { + crate::bind::define_property_call(hir, e).map(|call| call.1) + }; + argument.map_or(PropKey::None, PropKey::Computed) + } + /// The same for the property that represents `props`, the properties of one name in the members /// of a union or an intersection; `owner` has the first. `createUnionOrIntersectionProperty`: /// it takes the `nameType` of the first. If that has none it uses the declaration, and has one @@ -809,11 +842,10 @@ impl<'p, 's> Checker<'p, 's> { _ => None, }, AccessNode::IndexedAccessType(file, node) => match self.hir(file)[node].kind { - TypeNodeKind::IndexedAccess { index, .. } => Some(( - file, - self.hir(file)[index].pos, - self.end_of_type_node(file, index), - )), + TypeNodeKind::IndexedAccess { index, .. } => { + let start = start_of_type(self.hir(file), index); + Some((file, start, self.end_of_type_node_from(file, index, start))) + } _ => None, }, // For a computed name, the expression in the brackets. `["a"]` is stored as the name @@ -881,15 +913,17 @@ impl<'p, 's> Checker<'p, 's> { if let Some((prop, mapper)) = self.get_property_of_type(object, name) { if !access_flags.contains(AccessFlags::WRITING) { let prop_type = self.type_of_prop(prop, mapper); - return Some( - if matches!(access_node, AccessNode::IndexedAccessType(..)) - && self.contains_missing_type(prop_type) + return Some(match access_node { + AccessNode::ElementAccess(file, e) => { + self.flow_type_of_reference(file, e, prop_type) + } + AccessNode::IndexedAccessType(..) + if self.contains_missing_type(prop_type) => { self.union(&[prop_type, TypeId::UNDEFINED]) - } else { - prop_type - }, - ); + } + _ => prop_type, + }); } if let Some((file, e)) = access_expression && let ExprKind::Index { obj, .. } = self.hir(file)[e].kind @@ -903,10 +937,17 @@ impl<'p, 's> Checker<'p, 's> { let ty = self.write_type_of_prop(prop, mapper); let takes_undefined = prop.flags.contains(PropFlags::OPTIONAL) && !self.p.files.options.exact_optional_property_types; - return Some(if takes_undefined { + let prop_type = if takes_undefined { self.optional(ty) } else { ty + }; + // `getAssignmentTargetKind(accessExpression) != AssignmentKindDefinite` + return Some(match access_expression { + Some((file, e)) if access_flags.contains(AccessFlags::EXPRESSION_POSITION) => { + self.flow_type_of_reference(file, e, prop_type) + } + _ => prop_type, }); } if self.is_numeric_name(name) && self.every_type(object, |c, t| c.is_tuple(t)) { @@ -1225,11 +1266,32 @@ impl<'p, 's> Checker<'p, 's> { node: TypeNodeId, mapper: MapperId, alias: Option<(Sym, &[TypeId])>, + ) -> TypeId { + self.conditional_type_cached(file, node, mapper, alias, false) + } + + /// `is_member`: it is the `getConditionalType` that `getConditionalTypeInstantiation` calls for + /// a member of the union it distributes over, which reads no entry of `root.instantiations` + /// and assigns none. FOR SPEED: it shares the entries that it would compute again, see + /// `Program::conditionals`. + fn conditional_type_cached( + &mut self, + file: FileId, + node: TypeNodeId, + mapper: MapperId, + alias: Option<(Sym, &[TypeId])>, + is_member: bool, ) -> TypeId { let q = Query::Cond(file, node, mapper); if alias.is_none() - && let Some(known) = (self.p.conditionals).get(&self.task, &(file, node, mapper)) + && let Some((known, is_repeatable)) = + (self.p.conditionals).get(&self.task, &(file, node, mapper)) + && (is_repeatable || !is_member) { + // The call in progress assigns the entry again. + if !is_repeatable && self.may_be_in_flight(q) && self.stack.contains(&q) { + self.note_cycle(); + } return known; } if alias.is_none() @@ -1240,11 +1302,25 @@ impl<'p, 's> Checker<'p, 's> { if !self.enter(q) { return self.excessively_deep(); } + let mark = self.non_cacheable_mark(); let ty = self.conditional_type_uncached(file, node, mapper, false, alias); + let is_repeatable = self.non_cacheable_mark() == mark; match (self.leave(q), alias) { + (Ok(stored), None) if is_member => { + if is_repeatable { + (self.p.conditionals).insert( + &self.task, + (file, node, mapper), + (ty, true), + stored, + ); + } + ty + } // Where it was in progress several times, the outermost is the last to store. (Ok(stored), None) => { - (self.p.conditionals).rewrite(&self.task, (file, node, mapper), ty, stored); + let entry = (ty, is_repeatable); + (self.p.conditionals).rewrite(&self.task, (file, node, mapper), entry, stored); ty } (Err(open), None) => { @@ -1306,7 +1382,7 @@ impl<'p, 's> Checker<'p, 's> { let has_type_variables = (c.types().mapper_flags(one)) .contains(ObjectFlags::COULD_CONTAIN_TYPE_VARIABLES); if !has_type_variables && c.types().map(one, check_declared) == Some(part) { - return c.conditional_type(file, node, one); + return c.conditional_type_cached(file, node, one, None, true); } let for_constraint = MapperId::IDENTITY; c.resolve_conditional(file, node, one, distributed_over, for_constraint, None) @@ -1421,6 +1497,17 @@ impl<'p, 's> Checker<'p, 's> { pairs.extend_from_slice(mapping); pairs.extend(params.iter().copied().zip(inferred)); combined = self.types().mapper(pairs); + } else if params + .iter() + .any(|param| (self.p.type_param_constraints.get(&self.task, param)).is_none()) + { + // `instantiateType(root.extendsType, context.mapper)` fixes the `infer` type + // parameters in the extends type. FOR SPEED: nothing reads the result, so only + // what `getInferredType` resolves, which can close a cycle. + let mentioned = self.params_mentioned_in(extends_declared, ¶ms); + for (¶m, _) in params.iter().zip(mentioned).filter(|it| it.1) { + self.constraint_of_type_param(param); + } } } let extends_ty = self.instantiate(extends_declared, combined); @@ -1643,6 +1730,24 @@ impl<'p, 's> Checker<'p, 's> { &hir[m] } + /// `getNameTypeFromMappedType` for the mapped type as declared at `node`, which has an `as` + /// clause. `m.nameType` is assigned when the first request returns, whatever is in progress. A + /// later request reads it: it pushes no resolution and closes no cycle. + pub(super) fn declared_name_type_of_mapped( + &mut self, + file: FileId, + node: TypeNodeId, + ) -> TypeId { + let name = self.mapped_decl(file, node).name_ty; + if let Some(raw) = self.provisional_as_assigned(Query::TypeNode(file, name)) + && raw != u64::from(TypeId::UNRESOLVED.0) + && (self.p.type_node_types.get(&self.task, &(file, name))).is_none() + { + return TypeId(raw as u32); + } + self.type_from_node(file, name) + } + /// `getConstraintOfTypeParameter` for the parameter of the mapped type at `node`. fn constraint_of_mapped_param(&mut self, file: FileId, node: TypeNodeId) -> Option { if let Some(known) = (self.p.mapped_param_constraints).get(&self.task, &(file, node)) { @@ -1675,7 +1780,7 @@ impl<'p, 's> Checker<'p, 's> { // `pushTypeResolution` fails, every resolution above the first request is in the cycle. let key = (file, node, mapper); let mut in_progress = self.mapped_constraints_in_progress.iter(); - if let Some(&(_, height)) = in_progress.find(|it| it.0 == key) { + if let Some(&(_, height, _)) = in_progress.find(|it| it.0 == key) { if self.mark_cycle_from(height) { self.note_cycle(); self.task.closed_a_cycle = true; @@ -1684,9 +1789,13 @@ impl<'p, 's> Checker<'p, 's> { return TypeId::ERROR; } self.mapped_constraints_in_progress - .push((key, self.stack.len())); + .push((key, self.stack.len(), false)); let constraint = self.instantiated_constraint_of_mapped_param(file, node, mapper); - self.mapped_constraints_in_progress.pop(); + // `!popTypeResolution()` in `getResolvedBaseConstraint` + if (self.mapped_constraints_in_progress.pop()).is_some_and(|it| it.2) { + (self.p.circular_mapped_constraints).insert(&self.task, key, (), Stored::new()); + self.report_circular_mapped_key(file, node); + } // Afterwards: this may be the resolution in which the cycle was closed. match (self.p.circular_mapped_constraints).get(&self.task, &key) { Some(()) => TypeId::ERROR, @@ -1938,6 +2047,8 @@ impl<'p, 's> Checker<'p, 's> { nesting, }), is_array_literal: false, + is_array_pattern: false, + has_other_instantiation: false, }, ); } @@ -2004,6 +2115,8 @@ impl<'p, 's> Checker<'p, 's> { nesting: self.nesting_of_mapped_instantiation(), }), is_array_literal: false, + is_array_pattern: false, + has_other_instantiation: false, }, ) } @@ -2080,6 +2193,8 @@ impl<'p, 's> Checker<'p, 's> { nesting, }), is_array_literal: false, + is_array_pattern: false, + has_other_instantiation: false, }, ) }; @@ -2685,6 +2800,11 @@ impl<'p, 's> Checker<'p, 's> { ); let left = self.leave(q); if self.left_a_cycle { + // tsgo resolves the property later or never, with another `currentNode`. + if !self.eager.is_empty() { + self.mark_tainted_from(0); + return TypeId::ERROR; + } let stored = self.cycle_result(); let kept = (self.p.mapped_prop_types).insert( &self.task, @@ -2720,7 +2840,7 @@ impl<'p, 's> Checker<'p, 's> { let constraint = self.mapped_constraint(file, node, mapper); let mut shape = Shape::new_in(self.arena); let name_declared = if mapped.name_ty.is_some() { - Some(self.type_from_node(file, mapped.name_ty)) + Some(self.declared_name_type_of_mapped(file, node)) } else { None }; @@ -3029,21 +3149,30 @@ impl<'p, 's> Checker<'p, 's> { let rest = match (kind, chars.next()) { (StringMappingKind::Uppercase, _) => { text.chars() - .flat_map(char::to_uppercase) + .flat_map(to_uppercase_unicode_15) .for_each(&mut push); "" } // Not one character at a time: a sigma at the end of a word has a form of its own. + // A character that is not assigned ends a word. (StringMappingKind::Lowercase, _) => { - text.to_lowercase().chars().for_each(&mut push); + let mut word = 0; + for (at, unmapped) in text.char_indices() { + if is_cased_since_unicode_16(unmapped) { + let lower = text[word..at].to_lowercase(); + lower.chars().chain([unmapped]).for_each(&mut push); + word = at + unmapped.len_utf8(); + } + } + text[word..].to_lowercase().chars().for_each(&mut push); "" } (StringMappingKind::Capitalize, Some(first)) if i == 0 => { - first.to_uppercase().for_each(&mut push); + to_uppercase_unicode_15(first).for_each(&mut push); chars.as_str() } (StringMappingKind::Uncapitalize, Some(first)) if i == 0 => { - first.to_lowercase().for_each(&mut push); + to_lowercase_unicode_15(first).for_each(&mut push); chars.as_str() } _ => text, diff --git a/src/sema/check/mod.rs b/src/sema/check/mod.rs index cc863b6cbd92..e2d286642ddd 100644 --- a/src/sema/check/mod.rs +++ b/src/sema/check/mod.rs @@ -112,7 +112,7 @@ use spans::token_end; use spans::{is_word_at, word_at, word_end, word_start}; use spans::{skip_trivia_back, trim_trivia_end}; use std::sync::atomic::AtomicBool; -use symbols::AliasTarget; +use symbols::{AliasTarget, ExcludedMeanings}; use task::{Open, OrderDependent, Stored, Task}; pub use call::ResolvedCall; @@ -161,6 +161,7 @@ macro_rules! buffered_fields { type_predicates_from_body initializer_is_undefined circular_initializers circular_returns deferred_nodes resolved_parameter_symbols calls_before_signatures untyped_signatures_in_js jsx_fragment_types assignments_marked + blocks_too_large_for_flow_analysis ) }; } @@ -189,6 +190,9 @@ pub struct Program<'s> { /// declaration does not see what another one has marked, so `finish_file` takes back what it /// has reported. A union: it does not depend on which task comes first. properties_referenced_before: Guarded>, + /// What `check_external_emit_helpers_of_later_files` has reported, of all tasks. `finish_file` + /// keeps the first of each. It does not depend on which task comes first. + emit_helper_errors_of_earlier_files: Guarded>, /// `autoArrayType` auto_array_type: TypeId, pub files: &'s Files<'s>, @@ -229,6 +233,9 @@ pub struct Program<'s> { calls_before_signatures: ByNode<(FileId, ExprId), (), Buffered, &'s Session>, /// References whose control flow walk reached depth 2000 (2563). `getTypeAtFlowNode` flows_too_deep: ByNode<(FileId, ExprId), (), Buffered, &'s Session>, + /// The same for the references that are no expressions: a binding pattern, a function, the name + /// of a parameter, a synthesized access. `FindAncestor(reference, IsFunctionOrModuleBlock)`. + blocks_too_large_for_flow_analysis: ByKey<(FileId, Node), (), Buffered, &'s Session>, /// `getEffectsSignature`, by call. effects_signatures: ByNode<(FileId, ExprId), Option, Buffered, &'s Session>, /// `links.effectsSignature` of the calls `getEffectsSignature` has to resolve: generic or overloaded. @@ -260,9 +267,8 @@ pub struct Program<'s> { untyped_signatures_in_js: ByNode<(FileId, FnId), bool, Buffered, &'s Session>, declared_types: ByNode, shapes: ByIdIndirect, Buffered, &'s Session>, - /// `intersectionTypes`, for sets that contain a union. The key: the set, and - /// `IntersectionFlagsNoConstraintReduction`. - distributed_intersections: ByKey<(Box<[TypeId]>, bool), (TypeId, bool), Buffered, &'s Session>, + /// `intersectionTypes`, for sets that contain a union. + distributed_intersections: ByKey, sig_params: ByIdIndirect, Buffered, &'s Session>, sig_type_params: ByIdIndirect, Buffered, &'s Session>, /// `Signature.resolvedReturnType` of a signature with a `target`. @@ -328,7 +334,8 @@ pub struct Program<'s> { variances: ByNodeIndirect, /// `resolvedType` of a property declared by assignment declarations, keyed by the first /// declaration. - /// `awaited_no_alias` as a top-level query, once it is final. + /// `CachedTypeKindAwaitedType`. `None`: `awaited_no_alias` with an empty `awaitedTypeStack` has + /// no result. awaited_types: ById, Buffered, &'s Session>, /// `resolvedType` of a property of a mapped type, keyed by the mapped type and the property name. `getTypeOfMappedSymbol` mapped_prop_types: ByKey<(TypeId, Atom), TypeId, Buffered, &'s Session>, @@ -362,7 +369,9 @@ pub struct Program<'s> { type_param_defaults: ById, Buffered, &'s Session>, /// The type parameters whose `resolvedDefaultType` is `circularConstraintType`. circular_type_param_defaults: ById, - conditionals: ByKey<(FileId, TypeNodeId, MapperId), TypeId, Buffered, &'s Session>, + /// `ConditionalRoot.instantiations`, for the keys without an alias. The flag: nothing moved + /// `non_cacheable_mark` while the type was computed, so `getConditionalType` returns it again. + conditionals: ByKey<(FileId, TypeNodeId, MapperId), (TypeId, bool), Buffered, &'s Session>, /// The constraint of the parameter of each mapped type, if any. See /// `constraint_of_mapped_param`. mapped_param_constraints: ByNode<(FileId, TypeNodeId), Option, Buffered, &'s Session>, @@ -444,6 +453,7 @@ impl<'s> Program<'s> { closed_a_cycle: Default::default(), serial_variances: Guarded::new(map_in(session.arena())), properties_referenced_before: Default::default(), + emit_helper_errors_of_earlier_files: Default::default(), auto_array_type, types, expr_types: ByNode::new_in(&exprs, session), @@ -499,6 +509,7 @@ impl<'s> Program<'s> { deferred_nodes: ByNode::new_in(&exprs, session), jsx_fragment_types: ByKey::new_in(session), assignments_marked: ByKey::new_in(session), + blocks_too_large_for_flow_analysis: ByKey::new_in(session), jsx_attributes_types: ByNode::new_in(&exprs, session), call_diagnostics: ByNodeIndirect::new_in(&exprs, session), context_checked: ByNode::new_in(&fns, session), @@ -598,8 +609,6 @@ impl<'s> Program<'s> { stack: Vec::new(), in_progress: [0; 1024], frames: Vec::new(), - pending_circular_mapped_props: Vec::new(), - circular_mapped_props: Vec::new(), last_enter: EnterOutcome::Entered, resolution_start: 0, eager: Vec::new(), @@ -608,10 +617,15 @@ impl<'s> Program<'s> { array_or_tuple_constraint_requests: Vec::new(), mapped_instantiations_in_progress: Vec::new(), contextual_binding_patterns: Vec::new(), + requested_assignment_target: None, + looked_at_type_node: None, late_bound_members: Default::default(), late_bound_declarations: Default::default(), this_types: Default::default(), late_binding: Vec::new(), + late_binding_by_symbol: Vec::new(), + early_bound_for_good: Default::default(), + declared_members_in_progress: Vec::new(), reporting_nonexistent: Vec::new(), declared_index_infos_in_progress: Vec::new(), anonymous_members_in_place: Vec::new(), @@ -619,6 +633,7 @@ impl<'s> Program<'s> { enum_values_in_progress: Vec::new(), inheriting: Vec::new(), base_types_so_far: Vec::new(), + members_resolved_before_base_types: Vec::new(), mapped_constraints_in_progress: Vec::new(), serialization_level: 0, flow_type_cache: Default::default(), @@ -626,6 +641,8 @@ impl<'s> Program<'s> { flow_invocation_count: 0, discarded: None, non_existent_properties: Default::default(), + signatures_resolved_discarding: Vec::new(), + expressions_cached_discarding: Vec::new(), printing_closes_cycles: false, reprinting: false, printing_floors: Vec::new(), @@ -636,6 +653,8 @@ impl<'s> Program<'s> { stale_resolutions: Vec::new(), unpopped_resolutions: Default::default(), popped_for_symbol: None, + circular_before_parameter_symbol: Default::default(), + parameter_symbol_taken_as_unresolved: None, taints: 0, checked_type_references: (None, Vec::new()), taints_before_patterns: 0, @@ -699,6 +718,7 @@ impl<'s> Program<'s> { never_in_progress: Vec::new(), never_in_progress_from: Vec::new(), defaults_in_progress: Vec::new(), + identical_base_types_in_progress: Vec::new(), generic_object_flags: FxHashMap::default(), names_of_small_numbers: Default::default(), generic_mapped_types_in_progress: Vec::new(), @@ -715,6 +735,7 @@ impl<'s> Program<'s> { unions_of_union_types: Default::default(), constraint_stack: Vec::new(), constraints_marked_circular: Vec::new(), + circular_constraint_origins: Vec::new(), type_arguments_in_instantiation: Vec::new(), conditional_constraint_depth: 0, deepest_stack: std::cell::Cell::new(0), @@ -749,10 +770,12 @@ impl<'s> Program<'s> { undefined_properties: Default::default(), synthetic_default_import_types: Default::default(), referenced_properties: Default::default(), + tracked_names: Vec::new(), unused_private_members: Vec::new(), widening_contexts: Vec::new(), widened_types: Default::default(), iteration_types_cache: Default::default(), + reported_iteration_requests: Vec::new(), iife_resolving: Vec::new(), any_signature_reads: 0, any_signature_read_at: 0, @@ -766,9 +789,12 @@ impl<'s> Program<'s> { apparent_types_of_intersections: Default::default(), deferred_nodes: Default::default(), deferred_type_parameters: Vec::new(), - checked_class_expressions: Vec::new(), + emit_helpers_checked_early: Vec::new(), + emit_helpers_checked_elsewhere: Vec::new(), unresolved_identifiers: Vec::new(), unknown_symbols: Default::default(), + alias_targets_reported: Default::default(), + alias_targets_in_progress: Vec::new(), is_deferred_node: Default::default(), deferred_diagnostics: Vec::new(), save_deferred_diagnostics: false, @@ -863,7 +889,8 @@ enum Query { /// node. WriteType(FileId, TypeNodeId), /// The relation cache entry for two types, keyed by a hash of their printed names, which is the same in every task. Never on the - /// stack: it only owns the diagnostic of a stack depth overflow (`error_about_comparison_at_current_node`). + /// stack: it only owns the diagnostic of a stack depth overflow (`error_about_comparison_at_current_node`). Likewise the + /// entry of a `MappedProp` (`circular_mapped_property`). Comparison(u64), } @@ -1017,6 +1044,13 @@ struct QueryFrame { /// members there are then, so no type is stored here either. Not set where there is no next /// visit: see `note_members_in_place_read_above`. has_read_members_in_place: bool, + /// `getNarrowableTypeForReference` has come to `isConstraintPosition` under it: whether the + /// constraints are substituted depends on the check mode and on the contextual type. See + /// `is_rechecked`. + may_substitute_constraints: bool, + /// It is the `Query::Expr` under which `getQuickTypeOfExpression` runs. That is no + /// `checkExpression`: `c.currentNode` stays. + is_quick_type: bool, /// `Checker::current_source_element` when it was pushed. source_element: Option, } @@ -1056,17 +1090,15 @@ pub struct Checker<'p, 's> { /// How many entries of `stack` fall into each class. A query whose class is empty is not in /// progress. in_progress: [u16; 1024], - /// For each open `Query::MappedProp` that is part of a cycle: its index in `stack` and the type node to report 2615 at. - /// `circular_mapped_property` commits the entry when the query is left. - pending_circular_mapped_props: Vec<(usize, (FileId, TypeNodeId))>, - /// The cycles through a property of a mapped type that this task has found: the type node at which 2615 is reported, the - /// mapped type, the property. Until `check_circular_mapped_properties`. - circular_mapped_props: Vec<((FileId, TypeNodeId), TypeId, Atom)>, /// How the last `enter` ended. `leave` and `excessively_deep` reset it to `Entered`. last_enter: EnterOutcome, /// The patterns whose implied type is being computed as the contextual type of their /// initializer, and the stack depth when that began. contextual_binding_patterns: Vec<(FileId, PatId, usize)>, + /// `left` of the latest `getTypeOfExpression(left)` of `getContextualTypeForAssignmentExpression`. + requested_assignment_target: Option<(FileId, ExprId)>, + /// The type node whose type `look_at_type_node` is asking for. + looked_at_type_node: Option<(FileId, TypeNodeId)>, /// `membersAndExportsLinks`, keyed by container and side. late_bound_members: FxHashMap<(Sym, bool), late_bound::LateBoundMembers>, /// `symbolNodeLinks.Get(decl).resolvedSymbol != nil`: the declarations that `lateBindMember` has @@ -1079,6 +1111,16 @@ pub struct Checker<'p, 's> { /// container, and whether it is at the exports. See `is_late_binding`. Where `earlySymbols` is /// nil, only for the outermost one. late_binding: Vec<(usize, Sym, bool)>, + /// The containers, and whether it is the exports, for which `getLateBoundSymbol` is asking + /// `getMembersOfSymbol` or `getExportsOfSymbol` by itself. + late_binding_by_symbol: Vec<(Sym, bool)>, + /// `resolveDeclaredMembers` or `resolveAnonymousTypeMembers` has assigned `earlySymbols`, asked + /// by a computed name that was being bound for `late_binding_by_symbol`. No outer call of + /// theirs assigns the members again, so no type of the container has the late-bound ones. + early_bound_for_good: crate::util::FxHashSet<(Sym, bool)>, + /// The calls of `resolveDeclaredMembers` that are at `getMembersOfSymbol`. Each assigns + /// `declaredMembers` once the names are bound. See `gets_early_symbols_for_good`. + declared_members_in_progress: Vec, /// `nonExistentProperties`: property accesses whose 2339 message is being printed, with `stack.len()` when printing started. reporting_nonexistent: Vec<(FileId, ExprId, usize)>, /// `resolveDeclaredMembers` is at `getIndexInfosOfSymbol`, with `declaredMembersResolved` set. @@ -1104,14 +1146,19 @@ pub struct Checker<'p, 's> { inheriting: Vec, /// `resolvedBaseTypes` of each class or interface whose base types are being resolved. base_types_so_far: Vec<(Sym, Vec)>, + /// `ObjectFlagsMembersResolved` of a class or an interface whose members were resolved while + /// `getBaseTypes` was at it, which lasts until that returns: the key of the shape, the shape, + /// and the index of the entry of `base_types_so_far`. + members_resolved_before_base_types: Vec<(TypeId, &'p shape::Resolved<'p>, usize)>, /// `pushTypeResolution(key, ResolvedBaseConstraint)`, for the key of each mapped type whose - /// constraint type is being resolved, and the height of `stack` at that time. - mapped_constraints_in_progress: Vec<((FileId, TypeNodeId, MapperId), usize)>, + /// constraint type is being resolved, the height of `stack` at that time, and whether a cycle + /// has closed around it (`mark_cycle_from`). + mapped_constraints_in_progress: Vec<((FileId, TypeNodeId, MapperId), usize, bool)>, /// `c.serializationLevel`: how many `TypeToString` calls are in progress, counting those whose /// resolutions are made eagerly. serialization_level: u32, - /// `c.flowTypeCache`, for the loop back edge being traversed. `true`: the context-free type of the node (`c.contextFreeTypes`). - flow_type_cache: FxHashMap<(FileId, ExprId, bool), TypeId>, + /// `c.flowTypeCache`, for the loop back edge being traversed. + flow_type_cache: FxHashMap<(FileId, ExprId), TypeId>, /// `stack.len()` when that traversal began. `usize::MAX`: no back edge is being traversed. flow_type_cache_depth: usize, /// `c.flowInvocationCount` @@ -1121,6 +1168,13 @@ pub struct Checker<'p, 's> { /// `NodeCheckFlagsTypeChecked` on the name of a property access: its 2339 has been created. /// `true`: and discarded. non_existent_properties: FxHashMap<(FileId, ExprId), bool>, + /// The calls of the file being checked whose `links.resolvedSignature` was assigned at + /// `maxSerializationLevel`: what `resolveCall` reported in the callee, the type arguments and + /// the arguments is discarded, and nothing checks them again. + signatures_resolved_discarding: Vec, + /// The same for `links.resolvedType` of the expressions of the file being checked that + /// `is_checked_by_check_expression_cached`. + expressions_cached_discarding: Vec, /// The next `with_printer` is not a barrier for cycle detection: it prints when and what tsgo /// prints. printing_closes_cycles: bool, @@ -1165,6 +1219,12 @@ pub struct Checker<'p, 's> { unpopped_resolutions: crate::util::FxHashSet, /// What `pop_type_resolution` returned for a `Query::Pat`, for the `Query::Symbol` right below. popped_for_symbol: Option, + /// The binding elements that have their type from `reportCircularityError` since + /// `links.resolvedType` of the symbol of their parameter, which `is_resolved_on_request`, was + /// nil: a default in the pattern reads them while that symbol is resolved. + circular_before_parameter_symbol: crate::util::FxHashSet<(FileId, PatId)>, + /// `report_on_circular_pat` is at one of those: its parameter. + parameter_symbol_taken_as_unresolved: Option<(FileId, ParamId)>, /// Number of times frames were marked non-cacheable for any reason except `mark_tainted_by_pattern_from`. taints: u64, /// See `is_type_reference_checked`: the file, and a bit for each of its type nodes. @@ -1314,6 +1374,10 @@ pub struct Checker<'p, 's> { /// The type parameters whose `resolvedDefaultType` is `resolvingDefaultType`, each with the /// height of `stack` when that began. `true`: it has become `circularConstraintType`. defaults_in_progress: Vec<(TypeId, usize, bool)>, + /// The type references for which `getSingleBaseForNonAugmentingSubtype` has set + /// `ObjectFlagsIdenticalBaseTypeCalculated` and has not returned, each with the height of + /// `stack` when that began. + identical_base_types_in_progress: Vec<(TypeId, usize)>, /// The mapped types with an `as` clause for which `isGenericMappedType` is in progress. /// `ObjectFlagsIsGenericTypeComputed` with the two flags, of unions and intersections. generic_object_flags: FxHashMap, @@ -1339,6 +1403,9 @@ pub struct Checker<'p, 's> { /// The types whose `Query::Constraint` is in flight and was marked at a refused `enter`: `pushTypeResolution` marks every entry from /// the start of the cycle to the top of the stack. The `leave` of the frame takes the type out and stores the flag. constraints_marked_circular: Vec, + /// The type parameters whose constraint this task has found to be circular, each with `c.currentNode` at that moment. `None`: + /// under `eager`, or in a check after `check_source_file`. + circular_constraint_origins: Vec<(TypeId, Option)>, /// The deferred type references for which `resolve_type_arguments` is in `c.instantiateTypes(typeArguments, d.mapper)`, outermost first. /// One can be there many times: no `Query` is in flight at that point, as `popTypeResolution` has run. type_arguments_in_instantiation: Vec, @@ -1408,6 +1475,10 @@ pub struct Checker<'p, 's> { /// `symbolReferenceLinks` of the private members that an access in another file than that of /// their declaration has marked (`mark_property_as_referenced`). referenced_properties: crate::util::FxHashSet, + /// `Resolve` with `isUse` in `trackComputedName` and `trackExistingEntityName`: the file and + /// the scope it starts from, the name and the meaning. `check_unused` of that file resolves it + /// again. + tracked_names: Vec<(FileId, crate::bind::ScopeId, Atom, SymFlags)>, /// `Checked::unused_private_members` of the file that is being checked. unused_private_members: Vec<(Sym, u32)>, /// The contexts of the unions being widened. A `*WideningContext` is an index into it. @@ -1417,6 +1488,9 @@ pub struct Checker<'p, 's> { /// `iterationTypesCache`, by the type and `IterationUse::cache_flags`. The flag: tsgo has the /// entry too (`iterable_types`). iteration_types_cache: FxHashMap<(TypeId, u8), (symbols::Iter3, bool)>, + /// The keys of the entries whose request has reported something that a frame in progress may + /// still drop, each with `work` at that time, in that order (`settle_iteration_requests`). + reported_iteration_requests: Vec<(u64, (TypeId, u8))>, /// The calls of immediately invoked function expressions whose arguments are being checked to /// type the parameters. iife_resolving: Vec<(FileId, ExprId)>, @@ -1447,16 +1521,25 @@ pub struct Checker<'p, 's> { /// The class expressions that have two entries in `deferred_nodes`, the first for their type /// parameters, and whether `checkDeferredNodes` has come to the first. deferred_type_parameters: Vec<(ExprId, bool)>, - /// With `importHelpers`: the class expressions without a name of the file being checked, in the - /// order in which `checkClassExpression` first came to them, each with - /// `current_source_element` at that time. Until `check_external_emit_helpers`. - checked_class_expressions: Vec<(FileId, ExprId, Option)>, + /// With `importHelpers`: the expressions of the file being checked whose check calls + /// `checkExternalEmitHelpers` and came before their regular order, because something asked for + /// a type. In the order of those checks, each with `emit_helpers_order_of_early_check`. Until + /// `check_external_emit_helpers`. + emit_helpers_checked_early: Vec<(FileId, ExprId, (u32, u32))>, + /// The same for the expressions of files that are checked later than the file being checked, + /// in the order of those checks. + emit_helpers_checked_elsewhere: Vec<(FileId, ExprId)>, /// The identifiers `getResolvedSymbol` could not resolve, until /// `report_unresolved_identifiers`. unresolved_identifiers: Vec<(FileId, ExprId, Atom)>, /// `links.resolvedSymbol == c.unknownSymbol`, for the identifiers of the file being checked: /// the error of `onFailedToResolveSymbol` has been created. `true`: and discarded. unknown_symbols: FxHashMap, + /// The aliases that `check_target_of_alias_symbol` has reported on since `check_file` began: + /// `aliasSymbolLinks.aliasTarget != nil`, or `resolveAlias` is in progress. + alias_targets_reported: crate::util::FxHashSet, + /// Those for which `resolveAlias` is in progress. + alias_targets_in_progress: Vec, is_deferred_node: crate::util::FxHashSet, /// `deferredDiagnosticCallbacks`: the declarations for which `checkWeakMapSetCollision` or /// `checkReflectCollision` is deferred. The other callbacks are in `reported` @@ -1481,8 +1564,8 @@ pub struct Checker<'p, 's> { /// `getTypeFromBindingElement` has checked: `checkExpressionWithContextualType` stores no type. checked_with_contextual_type: Vec<(FileId, ExprId)>, /// `getContextualSignature` as `contextuallyCheckFunctionExpressionOrObjectLiteralMethod` got - /// it, before the inference context instantiates it, for the functions in which - /// `check_empty_binding_pattern` asks for it. + /// it, before the inference context instantiates it, for the functions for which + /// `contextual_param_type_at_check` is asked. contextual_signatures_at_check: Vec<((FileId, FnId), SigId)>, /// `discriminatedContextualTypes`: the result of `discriminate_by_object_members` for an object /// literal and a union, where it is final. @@ -1530,7 +1613,8 @@ pub struct Checker<'p, 's> { /// `note_parameter_types_resolved`. resolved_parameter_types: crate::util::FxHashSet<(SigId, u32)>, /// Ranges of `stack`: the resolutions of declarations whose initializer - /// `getQuickTypeOfExpression` is evaluating. See `is_flow_loop_visible`. + /// `getQuickTypeOfExpression` is evaluating, and those of a `...rest`. See + /// `is_flow_loop_visible`. quick_initializers: Vec<(usize, usize)>, /// `NodeCheckFlagsInCheckIdentifier`: the patterns for which `getNarrowedTypeOfSymbol` is in /// progress. @@ -1722,6 +1806,13 @@ impl<'p, 's> Checker<'p, 's> { false } + /// `is_stack_low` for the printer. It elides what is nested too deeply, which loses no error, so the check has not run out of + /// stack. It stops early enough for the queries that it makes. + #[inline] + pub(crate) fn is_stack_low_for_printing(&self) -> bool { + self.stack_base.saturating_sub(stack_pointer()) > self.stack_limit - self.stack_limit / 8 + } + /// Whether half of the stack that queries may use is in use. For a recursion that /// typescript-go ends at `instantiationCount`, on a stack that grows. #[inline] @@ -1790,6 +1881,8 @@ impl<'p, 's> Checker<'p, 's> { incomplete_flow, is_stored_by_nested_visit: false, has_read_members_in_place: false, + may_substitute_constraints: false, + is_quick_type: false, source_element: self.current_source_element, }); true @@ -1979,10 +2072,7 @@ impl<'p, 's> Checker<'p, 's> { // `contextuallyCheckFunctionExpressionOrObjectLiteralMethod` sets // `NodeCheckFlagsContextChecked` before it assigns the parameter types. The function // expression is checked again, and has its type at once. - if let Query::Expr(file, e) = q - && let ExprKind::Fn(func) = self.hir(file)[e].kind - && self.context_checking.iter().any(|c| c.0 == (file, func)) - { + if self.is_function_in_context_check(q) { return false; } // `getConditionalTypeInstantiation` has no re-entrancy check and caches its result only when it returns, so the conditional type @@ -2012,9 +2102,9 @@ impl<'p, 's> Checker<'p, 's> { // `checkExpression`, `checkPropertyAssignment`, `getTypeFromTypeNode` and, for a declaration // whose name is a pattern, `getTypeForVariableLikeDeclaration` have no re-entrancy guard. The // second visit takes `any` for the return type that is being resolved, does without the - // base constraint that is being resolved, or finds the members in place or the - // intersection as it is, and closes no cycle. Nor does it below a stale entry, where - // `findResolutionCycleStartIndex` stops. + // base constraint that is being resolved, or finds the members in place, the intersection + // as it is, no equivalent base type or a function that has its type at once, and closes no + // cycle. Nor does it below a stale entry, where `findResolutionCycleStartIndex` stops. // Or it comes to the `typeToStringEx` call that led here, with no type resolution on the way, // and prints one serialization level higher. That can close a cycle through what the first // call is resolving. At `maxSerializationLevel` the printer returns "?" and resolves nothing. @@ -2031,6 +2121,8 @@ impl<'p, 's> Checker<'p, 's> { || self.ends_at_members_in_place(i) || self.ends_at_reduction_in_progress(i) || self.ends_at_default_in_progress(i) + || self.ends_at_identical_base_type_in_progress(i) + || self.ends_at_function_in_context_check(i) || self.is_below_stale_resolution(i)) { return false; @@ -2054,7 +2146,12 @@ impl<'p, 's> Checker<'p, 's> { _ => from, }; if from < self.stack.len() { + let lowest_taint = self.lowest_taint; self.mark_tainted_from(from); + // A comparison that has asked for those members began below them: its result stays. + if matches!(q, Query::Bases(_)) { + self.lowest_taint = lowest_taint.min(from + 1); + } } // TypeScript does not detect an expression that is rechecked while it is being checked: it // follows the same path again, and the first resolution on that path is the one that @@ -2135,13 +2232,18 @@ impl<'p, 's> Checker<'p, 's> { if self.never_in_progress_from.is_empty() { return false; } - let mut from_here = self.stack[i..].iter(); - let resolution = from_here.position(|&q| self.is_resolution(q)); - let resolution = resolution.map_or(self.stack.len(), |at| i + at); + let resolution = self.first_resolution_from(i); let mut began = self.never_in_progress_from.iter(); began.any(|&height| height > i && height <= resolution) } + /// The index in `stack` of the first resolution from `stack[i]` up. `stack.len()`: none. + fn first_resolution_from(&self, i: usize) -> usize { + let mut from_here = self.stack[i..].iter(); + let resolution = from_here.position(|&q| self.is_resolution(q)); + resolution.map_or(self.stack.len(), |at| i + at) + } + /// Whether repeating the path from `stack[i]` ends before it reaches a resolution, at a type /// parameter whose default is being resolved: `getResolvedTypeParameterDefault` assigns /// `resolvingDefaultType` first, and returns `circularConstraintType` the next time. @@ -2149,13 +2251,44 @@ impl<'p, 's> Checker<'p, 's> { if self.defaults_in_progress.is_empty() { return false; } - let mut from_here = self.stack[i..].iter(); - let resolution = from_here.position(|&q| self.is_resolution(q)); - let resolution = resolution.map_or(self.stack.len(), |at| i + at); + let resolution = self.first_resolution_from(i); let mut began = self.defaults_in_progress.iter(); began.any(|&(_, height, _)| height > i && height <= resolution) } + /// Whether repeating the path from `stack[i]` ends before it reaches a resolution, at a type + /// reference whose base types `getSingleBaseForNonAugmentingSubtype` has requested: it sets + /// `ObjectFlagsIdenticalBaseTypeCalculated` first, and returns nil the next time. + fn ends_at_identical_base_type_in_progress(&self, i: usize) -> bool { + if self.identical_base_types_in_progress.is_empty() { + return false; + } + let resolution = self.first_resolution_from(i); + let mut began = self.identical_base_types_in_progress.iter(); + began.any(|&(_, height)| height > i && height <= resolution) + } + + /// Whether `q` is the check of a function expression or of a method of an object literal for + /// which `contextuallyCheckFunctionExpressionOrObjectLiteralMethod` has set + /// `NodeCheckFlagsContextChecked` and has not returned. + fn is_function_in_context_check(&self, q: Query) -> bool { + matches!(q, Query::Expr(file, e) + if matches!(self.hir(file)[e].kind, ExprKind::Fn(func) + if self.context_checking.iter().any(|c| c.0 == (file, func)))) + } + + /// Whether repeating the path from `stack[i]` ends before it reaches a resolution, at such a + /// function: it has its type at once, and neither its parameters nor its return type are asked + /// for again. Not for a request that tsgo may not make (`eager`). + fn ends_at_function_in_context_check(&self, i: usize) -> bool { + if self.context_checking.is_empty() || self.eager.iter().any(|&from| from > i) { + return false; + } + let resolution = self.first_resolution_from(i); + let mut before_first_resolution = self.stack[i..resolution].iter(); + before_first_resolution.any(|&q| self.is_function_in_context_check(q)) + } + /// Whether repeating the path from `stack[i]` ends before it reaches a resolution, at members /// that are already installed or at the values of an enum declaration that are being computed. fn ends_at_members_in_place(&self, i: usize) -> bool { @@ -2226,100 +2359,39 @@ impl<'p, 's> Checker<'p, 's> { bun_core::scoped_log!(SemaCycles, "CIRCLE {:?} in {:?}", q, &self.stack[i..]); } self.frames[j].circular = true; - if matches!(q, Query::MappedProp(..)) - && let Some(node) = self.first_checked_type_node(j) - { - match self - .pending_circular_mapped_props - .iter_mut() - .find(|pending| pending.0 == j) - { - Some(pending) => pending.1 = pending.1.min(node), - None => self.pending_circular_mapped_props.push((j, node)), - } - } + } + for in_progress in &mut self.mapped_constraints_in_progress { + in_progress.2 |= in_progress.1 > i; } true } - /// `c.currentNode` in `getTypeOfMappedSymbol` for the `Query::MappedProp` at `stack[frame]`, computed when a cycle through it - /// closes. tsgo reports 2615 at the node `checkSourceElement` is at when the property is first resolved, so the position follows - /// check order, not the order of queries here. Resolving any type node on the stack leads into the cycle, so the first of - /// them in check order is the answer. Type nodes are numbered children first, the order in which `checkSourceElement` - /// resolves them. - fn first_checked_type_node(&self, frame: usize) -> Option<(FileId, TypeNodeId)> { - // `checkExpression` makes its expression the current node until it returns. A type node is still current when the property - // is resolved only if no expression is checked on the way: up to `frame`, or around the cycle to the top of the stack. - let is_expr = |q: &Query| matches!(q, Query::Expr(..)); - let below = self.stack[..frame] - .iter() - .rposition(is_expr) - .map_or(0, |i| i + 1); - let above = self.stack[frame..] - .iter() - .rposition(is_expr) - .map_or(frame, |i| frame + i + 1); - let candidates = self.stack[below..frame].iter().chain(&self.stack[above..]); - candidates - .filter_map(|q| match *q { - Query::TypeNode(file, node) if self.is_resolved_by_check(file, node) => { - Some((file, node)) - } - _ => None, - }) - .min() - } - - /// Whether `checkSourceElement` resolves the type of `node` when it visits the node. `checkArrayType`, `checkTypeOperator`, - /// `checkConditionalType` and `checkInferType` only visit the children. Declaration files are not checked (`skipLibCheck`). - fn is_resolved_by_check(&self, file: FileId, node: TypeNodeId) -> bool { - let hir = self.hir(file); - hir.kind != FileKind::Declaration - && matches!( - hir[node].kind, - TypeNodeKind::Ref { .. } - | TypeNodeKind::Import { .. } - | TypeNodeKind::Typeof { .. } - | TypeNodeKind::Object(_) - | TypeNodeKind::Tuple(_) - | TypeNodeKind::Union(_) - | TypeNodeKind::Intersection(_) - | TypeNodeKind::Template { .. } - | TypeNodeKind::IndexedAccess { .. } - | TypeNodeKind::Mapped(_) - ) - } - - /// `getTypeOfMappedSymbol`: reports 2615 for the `Query::MappedProp` that was just left in a cycle. + /// The end of `getTypeOfMappedSymbol`, where `popTypeResolution` finds the cycle: 2615 at + /// `c.currentNode`. pub(super) fn circular_mapped_property(&mut self, mapped: TypeId, name: Atom) { - let frame = self.stack.len(); - if let Some(i) = self - .pending_circular_mapped_props - .iter() - .position(|pending| pending.0 == frame) - { - let (_, node) = self.pending_circular_mapped_props.swap_remove(i); - let stored = self.cycle_result(); - (self.p.mapped_types_with_errors).insert(&self.task, mapped, (), stored); - self.circular_mapped_props.push((node, mapped, name)); - } else if self.eager.is_empty() - && let Some(current) = self.current_node().or(self.current_source_element) - && !matches!(current, CurrentNode::TypeNode(..)) - // `resolveMappedTypeMembers` resolves the constraint `keyof R` first, and - // `resolveReverseMappedTypeMembers` the type of every property of the source of `R`. tsgo - // finds a cycle through one of those there, with no mapped symbol in progress. - && !(self.types().object_flags(mapped)).contains(ObjectFlags::HAS_REVERSE_MAPPED) - { - // `c.currentNode` is the expression that is being checked or, outside of one, the node - // `checkSourceElement` is at. - let at = self.place_of_current_node(current); - let property = match self.prop_ref(mapped, name) { - Some((prop, _)) => Arg::Prop(prop), - None => Arg::Atom(name), - }; - let diagnostic = self.new_diagnostic(at, 2615, &[property, Arg::Type(mapped)]); - self.add_diagnostic_of(Some(Query::MappedProp(mapped, name)), diagnostic); + // `resolveMappedTypeMembers` resolves the constraint `keyof R` first, and + // `resolveReverseMappedTypeMembers` the type of every property of the source of `R`. tsgo + // finds a cycle through one of those there, with no mapped symbol in progress. + if (self.types().object_flags(mapped)).contains(ObjectFlags::HAS_REVERSE_MAPPED) { + return; } + let at = match self.current_node().or(self.current_source_element) { + Some(current) => self.place_of_current_node(current), + // A check after `check_source_file`: see `error_at_current_node`. + None => match self.outermost_comparison.flatten() { + Some(error_node) => error_node, + None => return, + }, + }; + let property = match self.prop_ref(mapped, name) { + Some((prop, _)) => Arg::Prop(prop), + None => Arg::Atom(name), + }; + let diagnostic = self.new_diagnostic(at, 2615, &[property, Arg::Type(mapped)]); + // The id of `mapped` can be task-local, and each task is at a node of its own. + let declaration = self.mapped_origin(mapped).map(|it| (it.0, it.1)); + let entry = crate::util::fx_hash(&(diagnostic.code, declaration, &diagnostic.args)); + self.add_diagnostic_of(Some(Query::Comparison(entry)), diagnostic); } /// Whether `q` is a query TypeScript tracks as well (`TypeSystemPropertyName`): the type of a @@ -2485,18 +2557,26 @@ impl<'p, 's> Checker<'p, 's> { self.refused_at = self.work; } + /// Whether `q` is a call of `checkExpression`. A method or an accessor of an object literal is + /// no expression: `checkObjectLiteralMethod` calls + /// `checkFunctionExpressionOrObjectLiteralMethod` itself. + fn is_check_expression(&self, q: Query) -> bool { + matches!(q, Query::Expr(file, e) + if !matches!(self.hir(file)[e].kind, ExprKind::Fn(func) + if !matches!(self.hir(file)[func].kind, FnKind::Expr | FnKind::Arrow))) + } + /// `c.currentNode`. What `checkExpression` sets is derived from the queries in progress. /// `getTypeFromTypeNode` never sets it, but `checkSourceElement` visits a type node before /// anything resolves it: a type node in an expression (`checkAssertion`), the type arguments - /// of a call (`resolveCall`), and the type nodes that the checks after `check_source_file` + /// of a call (`resolveCall`), the signature of a function expression + /// (`looked_at_type_node`), and the type nodes that the checks after `check_source_file` /// query. A type node reached through any other query is resolved on demand and does not /// change `currentNode`. /// `None`: `currentNode` is what `checkSourceElement` set, see `current_source_element`. pub(super) fn current_node(&self) -> Option { - let innermost_expr = self - .stack - .iter() - .rposition(|q| matches!(q, Query::Expr(..))); + let innermost_expr = (self.stack.iter().zip(&self.frames)) + .rposition(|(&q, frame)| !frame.is_quick_type && self.is_check_expression(q)); // `checkSourceElement` has set it since the innermost `checkExpression` began. let before = innermost_expr.and_then(|i| self.frames[i].source_element); if self.current_source_element != before { @@ -2504,7 +2584,9 @@ impl<'p, 's> Checker<'p, 's> { } let mut inner = &self.stack[innermost_expr.unwrap_or(0)..]; let mut current = None; - if let [Query::Expr(file, e), rest @ ..] = inner { + if innermost_expr.is_some() + && let [Query::Expr(file, e), rest @ ..] = inner + { current = Some(CurrentNode::Expr(*file, *e)); if !matches!( self.hir(*file)[*e].kind, @@ -2515,7 +2597,9 @@ impl<'p, 's> Checker<'p, 's> { | ExprKind::New(_) | ExprKind::TaggedTemplate(_) | ExprKind::Jsx(_) - ) { + ) && !matches!(rest, [Query::TypeNode(of, node), ..] + if self.looked_at_type_node == Some((*of, *node))) + { return current; } inner = match rest { @@ -2534,15 +2618,21 @@ impl<'p, 's> Checker<'p, 's> { /// `IsPartOfTypeNode(c.currentNode)` fn is_current_node_part_of_type_node(&self) -> bool { - let (file, node) = match self.current_node().or(self.current_source_element) { - Some(CurrentNode::Expr(file, e)) => (file, self.hir(file).node(e)), - Some(CurrentNode::TypeNode(file, node)) => (file, self.hir(file).node(node)), - Some(CurrentNode::Node(file, node)) => (file, node), - None => return false, + let Some(current) = self.current_node().or(self.current_source_element) else { + return false; }; + let (file, node) = self.node_of_current_node(current); self.hir(file).is_part_of_type_node(node) } + fn node_of_current_node(&self, current: CurrentNode) -> (FileId, Node) { + match current { + CurrentNode::Expr(file, e) => (file, self.hir(file).node(e)), + CurrentNode::TypeNode(file, node) => (file, self.hir(file).node(node)), + CurrentNode::Node(file, node) => (file, node), + } + } + /// `GetErrorRangeForNode(c.currentNode)` fn place_of_current_node(&self, current: CurrentNode) -> (FileId, u32, u32) { match current { @@ -2553,7 +2643,8 @@ impl<'p, 's> Checker<'p, 's> { ), CurrentNode::TypeNode(file, node) => ( file, - self.hir(file)[node].pos, + self.hir(file) + .skip_trivia_of_node_at(self.hir(file)[node].pos), self.end_of_type_node(file, node), ), CurrentNode::Node(file, node) => { @@ -2941,10 +3032,6 @@ impl<'p, 's> Checker<'p, 's> { self.frames.last().is_some_and(|frame| frame.tainted) } - fn is_innermost_in_cycle(&self) -> bool { - self.frames.last().is_some_and(|frame| frame.circular) - } - /// The expressions of `file` grouped by kind, for callers that need a few kinds and would /// otherwise iterate over all expressions. It is built once per file. The handle borrows /// nothing: `let index = self.exprs_by_kind(file); for &e in index.of(ExprTag::Call)`. @@ -3127,6 +3214,17 @@ impl<'p, 's> Checker<'p, 's> { Some(entry.raw) } + /// `provisional` for a caller that reads what tsgo assigned when the computation returned. + /// Nothing is computed again, so a hit has no effect. `None` also for a result that depends on + /// more than a cycle and members in place. + fn provisional_as_assigned(&self, q: Query) -> Option { + let entry = self.provisional.get(&q)?; + let scope = self.frames.get(entry.depth as usize)?; + let is_valid = + scope.serial == entry.serial && entry.from != u32::MAX && entry.moved & !(1 | 32) == 0; + is_valid.then_some(entry.raw) + } + /// Increments `cycles`. #[inline] fn note_cycle(&mut self) { @@ -3169,7 +3267,7 @@ impl<'p, 's> Checker<'p, 's> { self.lowest_taint = self.lowest_taint.min(depth); self.note_taint_event(depth); // `getTypeOfVariableOrParameterOrProperty` stores what `getQuickTypeOfExpression` returns, - // which checks the callee with the loops visible. + // which checks the callee with the loops visible, and the type of a `...rest`. let quick = &self.quick_initializers; for (i, frame) in self.frames[depth..].iter_mut().enumerate() { if quick diff --git a/src/sema/check/print.rs b/src/sema/check/print.rs index 2b12e63896c0..1c5889235ff5 100644 --- a/src/sema/check/print.rs +++ b/src/sema/check/print.rs @@ -11,8 +11,8 @@ use super::errors_declaration_emit::{EndOfChain, Meaning}; use super::*; use crate::bind::{ClassOwner, Decl, FnOwner, MemberOwner, Parent, ScopeId, ScopeKind, SymbolId}; use crate::resolve::{displayed_path, remove_file_extension}; +use crate::verify::is_identifier_text; use bun_core::fmt::{ItoaBuf, VecWriter, digit_count, itoa}; -use bun_core::lexer::is_identifier; use bun_core::strings::{CodepointIterator, Cursor}; use core::fmt::Write; use std::ops::ControlFlow; @@ -37,6 +37,7 @@ const USE_STRUCTURAL_FALLBACK: u32 = 1 << 12; const MULTILINE_OBJECT_LITERALS: u32 = 1 << 13; const FORBID_INDEXED_ACCESS_SYMBOL_REFERENCES: u32 = 1 << 14; pub(super) const WRITE_TYPE_PARAMETERS_IN_QUALIFIED_NAME: u32 = 1 << 15; +const WRITE_ARRAY_AS_GENERIC_TYPE: u32 = 1 << 16; /// What `typeToString` hands `typeToStringEx`. pub(super) const TYPE_TO_STRING: u32 = ALLOW_UNIQUE_ES_SYMBOL_TYPE | USE_ALIAS_DEFINED_OUTSIDE_CURRENT_SCOPE; @@ -55,9 +56,6 @@ const NO_TRUNCATION_MAXIMUM_TRUNCATION_LENGTH: usize = 1_000_000; /// `any` with the synthetic leading comment of `createElidedInformationPlaceholder`. const ELIDED: &[u8] = b"/*elided*/ any"; -/// Maximum nesting depth for printing types of any kind. TypeScript has no such limit. -const MAXIMUM_DEPTH: u32 = 150; - /// `ast.TypePrecedence` const CONDITIONAL: u8 = 0; const FUNCTION: u8 = 2; @@ -75,6 +73,16 @@ impl Checker<'_, '_> { file: FileId, e: ExprId, ) -> Option> { + let (_, start, end) = self.place_of_assignment_declaration_name(file, e)?; + Some(self.source_text(file, start, end)) + } + + /// `GetNonAssignedNameOfDeclaration(e)` for an assignment or a call that declares a property. + pub(super) fn place_of_assignment_declaration_name( + &self, + file: FileId, + e: ExprId, + ) -> Option<(FileId, u32, u32)> { let hir = self.hir(file); let name = match hir[e].kind { // `module.exports = value` has no name. @@ -86,17 +94,19 @@ impl Checker<'_, '_> { } // `GetElementOrPropertyAccessName`, or else the whole left-hand side. ExprKind::Assign { target, .. } => match hir[target].kind { - ExprKind::Dot { name, name_pos, .. } if !is_private_name_at(hir, name_pos) => { - return Some(self.atom_text(name)); + ExprKind::Dot { name_pos, .. } if !is_private_name_at(hir, name_pos) => { + return Some(self.place_of_token(file, name_pos)); } - ExprKind::Index { index, .. } if is_string_or_numeric_literal_like(hir, index) => { + ExprKind::Index { index, .. } + if is_string_or_numeric_literal_like_in_parentheses(hir, index) => + { index } _ => target, }, _ => crate::bind::define_property_call(hir, e)?.1, }; - Some(self.source_text( + Some(( file, self.start_inside_parentheses(file, name), self.end_inside_parentheses(file, name), @@ -155,6 +165,11 @@ impl Checker<'_, '_> { self.printed(|c, out| c.write_type(out, ty, NO_TYPE_REDUCTION)) } + /// `typeToStringEx(t, nil, TypeFormatFlagsWriteArrayAsGenericType)`: `Array`, not `T[]`. + pub(super) fn type_to_string_with_generic_arrays(&mut self, ty: TypeId) -> Vec { + self.printed(|c, out| c.write_type(out, ty, WRITE_ARRAY_AS_GENERIC_TYPE)) + } + /// `t.symbol.ValueDeclaration`, if that is an expression (`ast.IsExpression`), and the scope /// from which names are resolved there. fn value_declaration_expression_of_type( @@ -271,7 +286,6 @@ impl Checker<'_, '_> { } /// `symbol.Parent` of the member `m`, if a class or an interface declares it. - #[cfg(feature = "baselines")] pub(super) fn symbol_of_member_owner(&self, file: FileId, m: MemberId) -> Option { let bound = self.bound(file); let container = match bound.member_owner[m.idx()] { @@ -360,7 +374,7 @@ impl Checker<'_, '_> { let flags = IGNORE_ERRORS | WRITE_TYPE_PARAMETERS_IN_QUALIFIED_NAME; let mut text = with_printer(self, None, None, flags, |printer| { printer.never_ascii_escape = true; - printer.signature_to_text(signature, kind, b"", false) + printer.signature_to_text(signature, kind, b"", false, None) }); out.append(&mut text); } @@ -497,6 +511,28 @@ impl<'p, 's> Checker<'p, 's> { }) } + /// `createExpressionFromSymbolChain(chain, len(chain)-1)`, as `symbolToStringEx` prints it under + /// `SymbolFormatFlagsAllowAnyNodeKind`. + pub(super) fn create_expression_from_symbol_chain( + &mut self, + chain: &[Sym], + enclosing_declaration: Enclosing, + never_ascii_escape: bool, + ) -> Vec { + let enclosing_declaration = + (!enclosing_declaration.is_none()).then_some(enclosing_declaration); + with_printer( + self, + enclosing_declaration, + None, + IGNORE_ERRORS, + |printer| { + printer.never_ascii_escape = never_ascii_escape; + printer.create_expression_from_symbol_chain(chain, chain.len() - 1) + }, + ) + } + /// `NodeBuilder.TryJSTypeNodeToTypeNode` pub(super) fn try_js_type_node_to_type_node( &mut self, @@ -514,7 +550,7 @@ impl<'p, 's> Checker<'p, 's> { flags, |printer| { printer - .try_reuse_type_node(file, node) + .try_reuse_type_node(file, node, 0) .map(|node| node.text) }, ) @@ -678,7 +714,6 @@ fn with_printer<'p, T>( reverse_mapped_stack: Vec::new(), mapper: MapperId::IDENTITY, enclosing_symbol_types: Vec::new(), - depth: 0, enclosing_declaration, enclosing_expression: None, tracker: tracker.map(|tracker| tracker as &mut dyn SymbolTracker<'p>), @@ -830,6 +865,158 @@ fn type_arguments_text(nodes: Vec) -> Vec { } } +/// `ast.OperatorPrecedence`. `Coalesce` is `LogicalOr`, `DisallowComma` is `Yield`. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +enum OperatorPrecedence { + Comma, + Spread, + Yield, + Assignment, + Conditional, + LogicalOr, + LogicalAnd, + BitwiseOr, + BitwiseXor, + BitwiseAnd, + Equality, + Relational, + Shift, + Additive, + Multiplicative, + Exponentiation, + Unary, + Update, + LeftHandSide, + OptionalChain, + Member, + Primary, + Parentheses, +} + +impl OperatorPrecedence { + /// `GetBinaryOperatorPrecedence`, and that of the comma. + fn of_binary_operator(op: BinOp) -> OperatorPrecedence { + match op { + BinOp::Comma => OperatorPrecedence::Comma, + BinOp::Nullish | BinOp::Or => OperatorPrecedence::LogicalOr, + BinOp::And => OperatorPrecedence::LogicalAnd, + BinOp::BitOr => OperatorPrecedence::BitwiseOr, + BinOp::BitXor => OperatorPrecedence::BitwiseXor, + BinOp::BitAnd => OperatorPrecedence::BitwiseAnd, + BinOp::EqEq | BinOp::NotEq | BinOp::EqEqEq | BinOp::NotEqEq => { + OperatorPrecedence::Equality + } + BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::In | BinOp::Instanceof => { + OperatorPrecedence::Relational + } + BinOp::Shl | BinOp::Shr | BinOp::UShr => OperatorPrecedence::Shift, + BinOp::Add | BinOp::Sub => OperatorPrecedence::Additive, + BinOp::Mul | BinOp::Div | BinOp::Rem => OperatorPrecedence::Multiplicative, + BinOp::Pow => OperatorPrecedence::Exponentiation, + } + } + + /// That of an access or a call, and the one its expression is emitted with. + fn of_chain(chain: Chain) -> OperatorPrecedence { + match chain { + Chain::No => OperatorPrecedence::Member, + Chain::Start | Chain::Continue => OperatorPrecedence::OptionalChain, + } + } + + /// `GetExpressionPrecedence` of `e` without the parentheses around it. + fn of_expression(hir: &hir::File, e: ExprId) -> OperatorPrecedence { + match hir[e].kind { + ExprKind::Spread(_) => OperatorPrecedence::Spread, + ExprKind::Yield { .. } => OperatorPrecedence::Yield, + ExprKind::Assign { .. } => OperatorPrecedence::Assignment, + ExprKind::Cond { .. } => OperatorPrecedence::Conditional, + ExprKind::Binary { op, .. } => OperatorPrecedence::of_binary_operator(op), + ExprKind::AsConst(operand) if !hir.is_type_assertion(e, operand) => { + OperatorPrecedence::Relational + } + ExprKind::Unary { + op: UnOp::PostInc | UnOp::PostDec, + .. + } => OperatorPrecedence::Update, + ExprKind::Unary { .. } + | ExprKind::Await(_) + | ExprKind::NonNull(_) + | ExprKind::AsConst(_) => OperatorPrecedence::Unary, + ExprKind::Dot { chain, .. } | ExprKind::Index { chain, .. } => { + OperatorPrecedence::of_chain(chain) + } + ExprKind::Call(call) => OperatorPrecedence::of_chain(hir[call].chain), + ExprKind::New(call) if hir[call].close_pos == u32::MAX => { + OperatorPrecedence::LeftHandSide + } + ExprKind::New(_) + | ExprKind::TaggedTemplate(_) + | ExprKind::ImportCall { .. } + | ExprKind::ImportMeta + | ExprKind::NewTarget(_) => OperatorPrecedence::Member, + _ => OperatorPrecedence::Primary, + } + } + + /// `getBinaryExpressionPrecedence`: those of the operands of `left op right`, and what + /// `emitBinaryExpression` does for operands that are synthesized. The right operand of a `+` or + /// a `*` that the parser creates is no `+` or `*`, so what applies to those is left out. + fn of_operands( + hir: &hir::File, + op: BinOp, + left: ExprId, + right: ExprId, + ) -> (OperatorPrecedence, OperatorPrecedence) { + let precedence = OperatorPrecedence::of_binary_operator(op); + let of_right = match precedence { + OperatorPrecedence::LogicalOr => OperatorPrecedence::LogicalAnd, + OperatorPrecedence::LogicalAnd => OperatorPrecedence::BitwiseOr, + OperatorPrecedence::Equality => OperatorPrecedence::Relational, + OperatorPrecedence::Relational => OperatorPrecedence::Shift, + OperatorPrecedence::Shift => OperatorPrecedence::Additive, + OperatorPrecedence::Additive => OperatorPrecedence::Multiplicative, + OperatorPrecedence::Multiplicative => OperatorPrecedence::Exponentiation, + _ => precedence, + }; + let of_left = match precedence { + OperatorPrecedence::Exponentiation => OperatorPrecedence::Update, + _ => precedence, + }; + // `mixingBinaryOperatorsRequiresParentheses` + let is_mixed_with = |operand: ExprId| match hir[operand].kind { + ExprKind::Binary { op: inner, .. } if !is_parenthesized(hir, operand) => matches!( + (op, inner), + (BinOp::Nullish, BinOp::And | BinOp::Or) | (BinOp::And | BinOp::Or, BinOp::Nullish) + ), + _ => false, + }; + let or_highest = |operand: ExprId, otherwise: OperatorPrecedence| { + if is_mixed_with(operand) { + OperatorPrecedence::Parentheses + } else { + otherwise + } + }; + (or_highest(left, of_left), or_highest(right, of_right)) + } +} + +/// `TokenToString` of the operator of a unary expression. +fn unary_operator_text(op: UnOp) -> &'static [u8] { + match op { + UnOp::Plus => b"+", + UnOp::Minus => b"-", + UnOp::BitNot => b"~", + UnOp::Not => b"!", + UnOp::Typeof => b"typeof", + UnOp::Void => b"void", + UnOp::Delete => b"delete", + UnOp::PreInc | UnOp::PostInc => b"++", + UnOp::PreDec | UnOp::PostDec => b"--", + } +} + #[derive(Copy, Clone, PartialEq, Eq)] enum SignatureKind { Call, @@ -849,9 +1036,22 @@ enum Identity { Function(FileId, FnId), /// A conditional type, or a deferred type reference. Node(FileId, TypeNodeId), + /// The symbol whose first declaration starts there (`Shape::symbol_declared_at`). + Declaration(FileId, u32), Type(TypeId), } +impl Identity { + /// An object literal is one symbol, whichever type has it: fresh, regular, widened, or created + /// from one of those. + fn of_object_literal(file: FileId, literal: ExprId) -> Identity { + let created_by = ObjectLiteralCheck::ForParent; + Identity::Origin(Origin::WidenedLiteral( + file, literal, false, created_by, false, + )) + } +} + /// `yieldModuleSymbol` of `lookupSymbolChain` #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub(super) enum YieldModuleSymbol { @@ -1028,7 +1228,6 @@ struct Printer<'c, 'p, 's> { /// `enclosingSymbolTypes` for signature declarations: the return type of each, while it is /// printed from its syntax. enclosing_symbol_types: Vec<((FileId, FnId), TypeId)>, - depth: u32, /// `enclosingDeclaration`: the scope from which names are resolved. `None` in error messages. enclosing_declaration: Option, /// The expression that is the enclosing declaration of `typeToStringEx`. @@ -1134,7 +1333,7 @@ pub(super) fn push_access( escapes_non_ascii: bool, ) { // `canUsePropertyAccess` - if is_identifier(name.strip_prefix(b"#").unwrap_or(name)) { + if is_identifier_text(name.strip_prefix(b"#").unwrap_or(name)) { expression.push(b'.'); expression.extend_from_slice(name); return; @@ -1468,13 +1667,10 @@ impl<'p, 's> Printer<'_, 'p, 's> { /// `typeToTypeNode` fn type_to_node(&mut self, ty: TypeId) -> Node { - if self.depth >= MAXIMUM_DEPTH || self.c.is_stack_low() { + if self.c.is_stack_low_for_printing() { return self.elided_information_placeholder(); } - self.depth += 1; - let node = self.type_to_node_worker(ty); - self.depth -= 1; - node + self.type_to_node_worker(ty) } fn type_to_node_worker(&mut self, ty: TypeId) -> Node { @@ -1659,7 +1855,13 @@ impl<'p, 's> Printer<'_, 'p, 's> { if *constraint != TypeId::UNKNOWN { return base; } - self.intrinsic_alias_to_node(b"NoInfer", &base) + match self + .c + .get_global_type_alias_symbol(known::NoInfer, 1, false) + { + Some(no_infer) => self.symbol_to_type_node(no_infer, false, vec![base]), + None => base, + } } TypeData::IndexedAccess { obj, index, .. } => { let object = self.type_to_node(*obj); @@ -1715,7 +1917,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { symbol.is_some().then(|| self.c.files().sym(file, symbol)) } - /// `symbolToTypeNode` of `Uppercase`, `NoInfer` and the like, with one type argument. + /// `symbolToTypeNode` of `Uppercase` and the like, with one type argument. fn intrinsic_alias_to_node(&mut self, name: &[u8], argument: &Node) -> Node { self.approximate_length += 2 * (name.len() + 1); Node { @@ -1794,7 +1996,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { Some(Identity::Function(file, function)) => { self.c.get_symbol_id_of_function(file, function); } - Some(Identity::Node(..) | Identity::Type(_)) | None => {} + Some(Identity::Node(..) | Identity::Declaration(..) | Identity::Type(_)) | None => {} } let key = self .enclosing_declaration @@ -1907,7 +2109,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { known::missing => b"\xEF\xBF\xBDmissing".to_vec(), name => self.text(name), }; - if is_identifier(&name) { + if is_identifier_text(&name) { return Node::simple(cat!(parent_name.text, b".", name)); } let literal = self.string_literal(&name, b'"'); @@ -1949,10 +2151,18 @@ impl<'p, 's> Printer<'_, 'p, 's> { /// `DeclarationNameToString`. The source text is used only for what `node.Text()` lacks, the escapes of an identifier. A name is not /// always at `start` (the name of an `@overload` is at the tag), and a missing name still has a token at that position. fn declaration_name_to_string(&self, file: FileId, name: hir::Node) -> Vec { - match self.get_text_of_node(file, name) { + let text = match self.get_text_of_node(file, name) { written if bun_core::strings::contains_char(written, b'\\') => written.to_vec(), _ => self.property_key_text(file, name), + }; + let hir = self.c.hir(file); + if hir.jsdoc_asterisks.is_empty() { + return text; } + // `GetTextOfNode` does not skip the `*` before the name. + let (start, end) = (hir.start(name), self.c.end_of_node(file, name)); + let from = super::spans::start_of_error_range(hir, start, end); + [&hir.text[from as usize..start as usize], &text[..]].concat() } /// The same for a clone of the name, which the printer emits as its `node.Text()`: an @@ -2826,6 +3036,14 @@ impl<'p, 's> Printer<'_, 'p, 's> { if let Some(element) = self.c.array_element(ty) { let is_readonly = self.c.global_type_symbol(known::ReadonlyArray) == Some(target); let element = self.type_to_node(element); + if self.flags & WRITE_ARRAY_AS_GENERIC_TYPE != 0 { + let name: &[u8] = if is_readonly { + b"ReadonlyArray" + } else { + b"Array" + }; + return Node::simple(cat!(name, type_arguments_text(vec![element]))); + } let array = cat!(element.emit(POSTFIX), b"[]"); return if is_readonly { Node::new(cat!(b"readonly ", array), TYPE_OPERATOR) @@ -3107,8 +3325,10 @@ impl<'p, 's> Printer<'_, 'p, 's> { has_fake_scope: self.has_fake_scope, mapper: self.mapper, }; - // `pushFakeScope("params", ..)`, which encloses that of the type parameters. - if expanded_parameters.iter().any(Option::is_some) { + // `pushFakeScope("params", ..)`, which encloses that of the type parameters. There is none + // for a signature without a declaration. + let declared = original_parameters.unwrap_or(expanded_parameters); + if !expanded_parameters.is_empty() && declared.iter().any(Option::is_some) { self.push_fake_scope(0); } if self.enclosing_declaration.is_some() { @@ -3579,9 +3799,10 @@ impl<'p, 's> Printer<'_, 'p, 's> { } self.visited_types.push(ty); // `tryReuseExistingNonParameterTypeNode`: `getTypeFromTypeNode(existing, true)` is - // nil if the mapper changes the type. + // nil if the mapper changes the type. `existing` is the query, inside any + // parentheses. let reused = match declared == ty { - true => self.try_reuse_type_node(file, node), + true => self.try_reuse_type_node(file, node, self.c.hir(file)[node].pos), false => None, }; self.visited_types.retain(|&visited| visited != ty); @@ -3606,14 +3827,13 @@ impl<'p, 's> Printer<'_, 'p, 's> { } return self.symbol_to_type_node(symbol, true, Vec::new()); } - // An object literal is one symbol, fresh, regular or widened. - Identity::Origin(match origin { + match origin { Origin::ObjectLiteral(file, literal, ..) | Origin::WidenedLiteral(file, literal, ..) => { - Origin::WidenedLiteral(file, literal, false, false, false) + Identity::of_object_literal(file, literal) } - _ => origin, - }) + _ => Identity::Origin(origin), + } } TypeData::Fns { decls, .. } => match decls.first() { Some(&(file, func)) => Identity::Function(file, func), @@ -3627,6 +3847,25 @@ impl<'p, 's> Printer<'_, 'p, 's> { } Identity::Instance(target) } + TypeData::Synth(shape) => { + if let Some(symbol) = shape.symbol + && self.should_emit_type_of_symbol(symbol, SymFlags::VALUE) + { + return self.symbol_to_type_node(symbol, true, Vec::new()); + } + match shape.symbol_declared_at { + Some((file, _, e)) if e.is_some() => match self.c.hir(file)[e].kind { + ExprKind::Class(class) => { + let symbol = self.c.bound(file).class_symbol[class.idx()]; + Identity::Origin(Origin::ClassStatic(self.c.files().sym(file, symbol))) + } + _ => Identity::of_object_literal(file, e), + }, + Some((file, pos, _)) => Identity::Declaration(file, pos), + // `getInstantiatedTypePart` creates a symbol. + None => Identity::Type(shape.instantiation_target.unwrap_or(ty)), + } + } _ => Identity::Type(ty), }; if let Some(symbol) = self.should_write_type_of_function_symbol(ty) { @@ -3670,9 +3909,11 @@ impl<'p, 's> Printer<'_, 'p, 's> { self.approximate_length += 2; return Node::simple(b"{}"); } - ([only], []) => return self.signature_to_node(*only, SignatureKind::FunctionType), + ([only], []) => { + return self.signature_to_node(*only, SignatureKind::FunctionType, ty); + } ([], [only]) => { - return self.signature_to_node(*only, SignatureKind::ConstructorType); + return self.signature_to_node(*only, SignatureKind::ConstructorType, ty); } _ => {} } @@ -3716,7 +3957,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { // type literal. No type is created here for a signature, nor for the rest. let to_node = |printer: &mut Self, index: usize| match abstract_signatures.get(index) { Some(&signature) => { - printer.signature_to_node(signature, SignatureKind::ConstructorType) + printer.signature_to_node(signature, SignatureKind::ConstructorType, ty) } None => printer.type_literal_to_node( ty, @@ -3737,8 +3978,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { /// `propertySymbol.Flags&SymbolFlagsPrototype != 0` for a property of `owner`. fn is_prototype_property(&self, owner: TypeId, property: &Prop) -> bool { - property.name == known::prototype - && matches!(property.source, PropSource::Type(_)) + self.c.is_prototype_of_class(property) && matches!( self.c.data(owner), TypeData::Anon { @@ -3921,11 +4161,12 @@ impl<'p, 's> Printer<'_, 'p, 's> { } let mut elements = Vec::new(); for &signature in call { - let text = self.signature_to_text(signature, SignatureKind::Call, b"", false); + let text = self.signature_to_text(signature, SignatureKind::Call, b"", false, Some(ty)); elements.push(cat!(text, b";")); } for &signature in construct { - let text = self.signature_to_text(signature, SignatureKind::Construct, b"", false); + let kind = SignatureKind::Construct; + let text = self.signature_to_text(signature, kind, b"", false, Some(ty)); elements.push(cat!(text, b";")); } let is_reverse_mapped = matches!(self.c.data(ty), TypeData::ReverseMapped { .. }); @@ -3980,10 +4221,10 @@ impl<'p, 's> Printer<'_, 'p, 's> { }); } let last = &properties[properties.len() - 1]; - self.add_property_to_element_list(ty, last, mapper, &mut elements); + self.add_property_to_element_list(last, mapper, &mut elements); break; } - self.add_property_to_element_list(ty, property, mapper, &mut elements); + self.add_property_to_element_list(property, mapper, &mut elements); } elements } @@ -4191,54 +4432,84 @@ impl<'p, 's> Printer<'_, 'p, 's> { members.collect() } - /// The syntax of the name in each declaration of `prop`. - fn property_name_syntaxes(&mut self, prop: &Prop, out: &mut Vec) { + /// `isStringNamed` and `isSingleQuotedStringNamed` for a declaration that is not a member of + /// an object literal. + fn name_syntax_of_declaration( + &mut self, + file: FileId, + declaration: Decl, + ) -> PropertyNameSyntax { + let hir = self.c.hir(file); let plain = PropertyNameSyntax { is_string: false, is_single_quoted: false, is_computed: false, }; - for_each_declared(prop, &mut |prop| { - match &prop.source { - PropSource::Symbol(symbol) => { - let list = self.c.members_of_symbol(*symbol); - let assignments = match list.is_empty() { - true => self.c.assignments_of_symbol(*symbol), - false => smallvec::SmallVec::new(), + // `ast.IsStringLiteral(name)` for a name whose first token is at `start`. + let name_at = |start: u32| { + let first = hir.text.get(start as usize).copied(); + PropertyNameSyntax { + is_string: matches!(first, Some(b'"' | b'\'')), + is_single_quoted: first == Some(b'\''), + is_computed: false, + } + }; + // `name.Expression()` of a `ComputedPropertyName`, or `ArgumentExpression` of an + // `ElementAccessExpression`. + let (key, is_computed) = match declaration { + Decl::Member(member) => match hir[member].key { + PropKey::Computed(e) => (e, true), + _ => { + return PropertyNameSyntax { + is_string: hir[member].flags.contains(Flags::STRING_NAME), + ..name_at(hir[member].name_pos) }; - if list.is_empty() && assignments.is_empty() { - out.push(plain); - } - for &declaration in assignments.iter() { - let hir = self.c.hir(symbol.file); - let is_string = match hir[declaration].kind { - ExprKind::Assign { target, .. } => match hir[target].kind { - ExprKind::Index { index, .. } => { - let key = self.c.type_of_expr(symbol.file, index); - self.c.is_string_like(key) - } - _ => false, - }, - _ => false, + } + }, + Decl::Expando(e) | Decl::ThisProperty(e) | Decl::ExportsProperty(e) => { + let PropKey::Computed(name) = self.c.key_of_assignment_declaration(file, e) else { + return plain; + }; + // `GetElementOrPropertyAccessName`, which skips parentheses. + if crate::bind::string_literal_text(hir, name).is_some() + || matches!(hir[name].kind, ExprKind::Number(_)) + { + return name_at(hir[name].pos); + } + (name, false) + } + _ => { + let node = hir.node(declaration); + let name = hir.name(node); + match hir.key_of(node) { + (PropKey::Computed(e), _) => (e, true), + (_, NameKind::ComputedString) => { + return PropertyNameSyntax { + is_string: true, + ..plain }; - out.push(PropertyNameSyntax { is_string, ..plain }); } - for &(file, member) in list.iter() { - let hir = self.c.hir(file); - let member = &hir[member]; - let (is_string, is_computed) = match member.key { - PropKey::Computed(e) => { - let key = self.c.type_of_expr(file, e); - (self.c.is_string_like(key), true) - } - _ => (member.flags.contains(Flags::STRING_NAME), false), - }; - out.push(PropertyNameSyntax { - is_string, - is_single_quoted: hir.text.get(member.name_pos as usize) - == Some(&b'\''), - is_computed, - }); + _ if name.is_some() => return name_at(hir.start(name)), + _ => return plain, + } + } + }; + let key = self.c.type_of_expr(file, key); + PropertyNameSyntax { + is_string: self.c.is_string_like(key), + is_computed, + ..plain + } + } + + /// The syntax of the name in each declaration of `prop`. + fn property_name_syntaxes(&mut self, prop: &Prop, out: &mut Vec) { + for_each_declared(prop, &mut |prop| { + match &prop.source { + PropSource::Symbol(symbol) => { + let declarations = self.c.declarations_of_property(*symbol); + for &(file, declaration) in declarations.iter() { + out.push(self.name_syntax_of_declaration(file, declaration)); } } PropSource::Literal(file, written) => { @@ -4282,7 +4553,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { b'"' }; let has_name_type = self.has_name_type(prop); - let is_identifier = is_identifier(&name); + let is_identifier = is_identifier_text(&name); let is_numeric = self.c.is_numeric_name(prop.name); // `getPropertyNameNodeForSymbolFromNameType` if has_name_type @@ -4329,7 +4600,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { } let text = bytes.to_vec(); let is_numeric = self.c.is_numeric_name(name); - if !is_identifier(&text) && !is_numeric { + if !is_identifier_text(&text) && !is_numeric { return quoted(&text, b'"', false); } if is_numeric && text.starts_with(b"-") { @@ -4601,13 +4872,15 @@ impl<'p, 's> Printer<'_, 'p, 's> { let meaning = SymFlags::VALUE | SymFlags::EXPORT_VALUE; // A name that does not resolve where the type is printed is tracked as the symbol it // resolves to in its source position, which should be inaccessible. - let symbol = files - .resolve_name(at.file, at.scope, name, meaning) - .or_else(|| { - let scope = self.c.enclosing_scope_of_expr(file, first_identifier); - files.resolve_name(file, scope, name, meaning) - }); + let mut location = (at.file, at.scope); + let mut symbol = files.resolve_name(location.0, location.1, name, meaning); + if symbol.is_none() { + location = (file, self.c.enclosing_scope_of_expr(file, first_identifier)); + symbol = files.resolve_name(location.0, location.1, name, meaning); + } if let Some(symbol) = symbol { + self.c + .note_use_of_tracked_name(location.0, location.1, name, meaning); self.track_symbol(symbol, SymFlags::VALUE); } } @@ -4616,7 +4889,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { fn track_parameter_declaration_name(&mut self, file: FileId, parameter: ParamId) { let hir = self.c.hir(file); let name = hir[parameter].pat; - if self.tracker.is_some() + if self.enclosing_declaration.is_some() && name.is_some() && matches!(hir[name].kind, PatKind::Object(_) | PatKind::Array(_)) { @@ -4655,15 +4928,13 @@ impl<'p, 's> Printer<'_, 'p, 's> { /// `addPropertyToElementList` fn add_property_to_element_list( &mut self, - owner: TypeId, prop: &Prop, mapper: MapperId, elements: &mut Vec>, ) { - let reverse_mapped = if matches!(self.c.data(owner), TypeData::ReverseMapped { .. }) { - Some(self.reverse_mapped_property(owner, prop.name)) - } else { - None + let reverse_mapped = match prop.source { + PropSource::ReverseMapped(of, _) => Some(self.reverse_mapped_property(of, prop.name)), + _ => None, }; let uses_placeholder = reverse_mapped .as_ref() @@ -4681,10 +4952,9 @@ impl<'p, 's> Printer<'_, 'p, 's> { if self.c.atoms().is_symbol_name(prop.name) { self.track_late_bound_name(prop); } - let declared = if reverse_mapped.is_some() { - self.property_with_declarations(owner, prop.name) - } else { - None + let declared = match &reverse_mapped { + Some(property) => self.property_with_declarations(property.owner, prop.name), + None => None, }; let name = match declared { Some(mut declared) => { @@ -4710,7 +4980,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { }; let signature = self.c.sig_of_fn(file, func); let signature = self.c.instantiate_sig(signature, symbol_mapper); - let text = self.signature_to_text(signature, kind, &name, false); + let text = self.signature_to_text(signature, kind, &name, false, None); elements.push(cat!(self.comments_before(file, declaration), text, b";")); } return; @@ -4748,6 +5018,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { SignatureKind::Method, &name, is_optional, + None, ); // `core.Coalesce(signature.declaration, propertySymbol.ValueDeclaration)` let origin = self.c.types().sig_origin(signature); @@ -4778,7 +5049,7 @@ impl<'p, 's> Printer<'_, 'p, 's> { if let Some(property) = reverse_mapped { self.reverse_mapped_stack.push(property); } - let node = self.serialize_type_of_property(owner, prop, property_type); + let node = self.serialize_type_of_property(prop, property_type); if reverse_mapped.is_some() { self.reverse_mapped_stack.pop(); } @@ -4809,28 +5080,202 @@ impl<'p, 's> Printer<'_, 'p, 's> { quoted(self.c.atoms().bytes(text), quote, false) } - /// What the printer emits for a deep clone of the expression `e` of `file`. No node of a clone - /// has a position, so `getTextOfNode` and `getLiteralText` emit `node.Text()`. `None`: `e` is - /// neither a literal nor an entity name. - fn cloned_expression_text(&self, file: FileId, e: ExprId) -> Option> { + /// `emitTemplateLiteral` for a deep clone of `template` of `file`. `RawText` of each piece is + /// what the source has. + fn cloned_template_text(&self, file: FileId, template: ExprId) -> Option> { let hir = self.c.hir(file); - let text = match hir[e].kind { - ExprKind::Ident(name) => self.text(name), - ExprKind::Dot { .. } if is_property_access_entity_name_expression(hir, e) => { - self.entity_name_text(file, e)? + let ExprKind::Template { exprs } = hir[template].kind else { + return None; + }; + // The `` ` `` or the `}` that the next piece starts with. + let mut at = hir[template].pos as usize; + let mut text = Vec::new(); + for substitution in hir.ids(exprs) { + let (end, is_substitution) = super::spans::template_text(&hir.text, at + 1); + if !is_substitution { + return None; + } + text.extend_from_slice(hir.text.get(at..end)?); + let precedence = OperatorPrecedence::Comma; + text.extend_from_slice(&self.cloned_expression_text(file, substitution, precedence)?); + let end = self.c.end_of_expr(file, substitution); + at = self.c.skip_trivia_from(file, end) as usize; + if hir.text.get(at) != Some(&b'}') { + return None; + } + } + let (end, is_substitution) = super::spans::template_text(&hir.text, at + 1); + let last = hir.text.get(at..end)?; + if is_substitution || last.len() < 2 || !last.ends_with(b"`") { + return None; + } + text.extend_from_slice(last); + Some(text) + } + + /// `emitExpression(node, precedence)` for a deep clone of the expression `e` of `file`. No node + /// of a clone has a position, so `getTextOfNode` and `getLiteralText` emit `node.Text()` and + /// everything is on one line. `None`: it contains an object or array literal, a function, a + /// class, JSX or a type node, which have emitters of their own. + fn cloned_expression_text( + &self, + file: FileId, + e: ExprId, + precedence: OperatorPrecedence, + ) -> Option> { + use OperatorPrecedence as P; + if self.c.is_stack_low() { + return None; + } + let hir = self.c.hir(file); + let emit = |e: ExprId, precedence: P| self.cloned_expression_text(file, e, precedence); + // `emitArgument` of each: `LFCallExpressionArguments` + let emit_arguments = |list: IdList| -> Option> { + let list = hir.ids(list).map(|argument| emit(argument, P::Spread)); + let list = list.collect::>>>()?; + Some(cat!(b"(", list.join(&b", "[..]), b")")) + }; + let question_dot = |chain: Chain| -> &'static [u8] { + match chain { + Chain::Start => b"?.", + Chain::No | Chain::Continue => b"", } - ExprKind::Number(n) => crate::atom::number_to_string(hir.numbers[n as usize]), + }; + let text = match hir[e].kind { + ExprKind::Ident(name) | ExprKind::PrivateIdentifier(name) => self.text(name), + ExprKind::This => b"this".to_vec(), + ExprKind::Super => b"super".to_vec(), + ExprKind::Null => b"null".to_vec(), + ExprKind::True => b"true".to_vec(), + ExprKind::False => b"false".to_vec(), + ExprKind::Number(_) | ExprKind::BigInt(_) => self.text_of_number_literal(file, e), ExprKind::String(value) => self.cloned_string_literal_text(file, value, hir[e].pos), - ExprKind::Unary { op, operand } - if matches!(op, UnOp::Plus | UnOp::Minus) - && matches!(hir[operand].kind, ExprKind::Number(_)) => - { - let sign: &[u8] = if op == UnOp::Plus { b"+" } else { b"-" }; - cat!(sign, self.cloned_expression_text(file, operand)?) + ExprKind::Regex => { + let written = hir.text.get(hir[e].pos as usize..hir[e].end as usize)?; + written.to_vec() + } + ExprKind::Template { .. } => self.cloned_template_text(file, e)?, + ExprKind::TaggedTemplate(call) if hir[call].type_args.is_empty() => { + let template = self.cloned_template_text(file, hir[call].template)?; + cat!(emit(hir[call].callee, P::Member)?, b" ", template) + } + ExprKind::Dot { + obj, name, chain, .. + } => { + let object = emit(obj, P::of_chain(chain))?; + // `mayNeedDotDotForPropertyAccess`. `TokenFlagsWithSpecifier`: `0x`, `0b`, `0o`. + let written = hir.text.get(hir[obj].pos as usize..).unwrap_or_default(); + let may_need_dot_dot = matches!(hir[obj].kind, ExprKind::Number(_)) + && !is_parenthesized(hir, obj) + && !matches!(written, [b'0', b'x' | b'X' | b'b' | b'B' | b'o' | b'O', ..]) + && bun_core::strings::index_of_any(&object, b".eE").is_none(); + let dot: &[u8] = match chain { + Chain::Start => b"?.", + _ if may_need_dot_dot => b"..", + _ => b".", + }; + cat!(object, dot, self.text(name)) + } + ExprKind::Index { obj, index, chain } => { + let object = emit(obj, P::of_chain(chain))?; + let index = emit(index, P::Comma)?; + cat!(object, question_dot(chain), b"[", index, b"]") + } + ExprKind::Call(call) if hir[call].type_args.is_empty() => { + let call = &hir[call]; + // `emitCallee`: `isNewExpressionWithoutArguments` + let callee = match P::of_expression(hir, call.callee) { + P::LeftHandSide => emit(call.callee, P::Parentheses)?, + _ => emit(call.callee, P::of_chain(call.chain))?, + }; + cat!(callee, question_dot(call.chain), emit_arguments(call.args)?) + } + ExprKind::New(call) if hir[call].type_args.is_empty() => { + let call = &hir[call]; + let is_call = matches!( + hir[call.callee].kind, + ExprKind::Call(_) | ExprKind::ImportCall { .. } + ); + let callee = emit( + call.callee, + if is_call { P::Parentheses } else { P::Member }, + )?; + // `LFOptionalIfNil` + if call.close_pos == u32::MAX { + cat!(b"new ", callee) + } else { + cat!(b"new ", callee, emit_arguments(call.args)?) + } + } + ExprKind::Unary { + op: op @ (UnOp::PostInc | UnOp::PostDec), + operand, + } => cat!(emit(operand, P::LeftHandSide)?, unary_operator_text(op)), + ExprKind::Unary { op, operand } => { + let inner = match hir[operand].kind { + ExprKind::Unary { op: inner, .. } if !is_parenthesized(hir, operand) => { + Some(inner) + } + _ => None, + }; + let space: &[u8] = match (op, inner) { + (UnOp::Typeof | UnOp::Void | UnOp::Delete, _) + | (UnOp::Plus, Some(UnOp::Plus | UnOp::PreInc)) + | (UnOp::Minus, Some(UnOp::Minus | UnOp::PreDec)) => b" ", + _ => b"", + }; + cat!(unary_operator_text(op), space, emit(operand, P::Unary)?) + } + ExprKind::Binary { op, left, right } => { + let (of_left, of_right) = P::of_operands(hir, op, left, right); + let (left, right) = (emit(left, of_left)?, emit(right, of_right)?); + let space: &[u8] = if op == BinOp::Comma { b"" } else { b" " }; + let operator = super::errors::operator_text(op, false); + cat!(left, space, operator, b" ", right) + } + ExprKind::Assign { op, target, value } => { + let operator = match op { + Some(op) => super::errors::operator_text(op, true), + None => b"=".to_vec(), + }; + let (target, value) = (emit(target, P::Conditional)?, emit(value, P::Yield)?); + cat!(target, b" ", operator, b" ", value) + } + ExprKind::Cond { test, yes, no } => { + let (test, yes, no) = ( + emit(test, P::LogicalOr)?, + emit(yes, P::Yield)?, + emit(no, P::Yield)?, + ); + cat!(test, b" ? ", yes, b" : ", no) + } + ExprKind::Spread(operand) => cat!(b"...", emit(operand, P::Yield)?), + ExprKind::Await(operand) => cat!(b"await ", emit(operand, P::Unary)?), + ExprKind::Yield { value, star } => { + let keyword: &[u8] = if star { b"yield*" } else { b"yield" }; + if value.is_some() { + cat!(keyword, b" ", emit(value, P::Yield)?) + } else { + keyword.to_vec() + } } + ExprKind::NonNull(operand) => cat!(emit(operand, P::Member)?, b"!"), + ExprKind::AsConst(operand) if hir.is_type_assertion(e, operand) => { + cat!(b"", emit(operand, P::Update)?) + } + ExprKind::AsConst(operand) => cat!(emit(operand, P::Relational)?, b" as const"), + ExprKind::ImportCall { args } if hir.type_args_of_import_call(args).is_empty() => { + cat!(b"import", emit_arguments(args)?) + } + ExprKind::ImportMeta => b"import.meta".to_vec(), + ExprKind::NewTarget(name) => cat!(b"new.", self.text(name)), _ => return None, }; - let parentheses = parentheses_around(hir, e).len(); + let written = parentheses_around(hir, e).len(); + let parentheses = match written { + 0 => usize::from(P::of_expression(hir, e) < precedence), + _ => written, + }; Some(cat!( b"(".repeat(parentheses), text, @@ -4843,8 +5288,10 @@ impl<'p, 's> Printer<'_, 'p, 's> { let hir = self.c.hir(file); let name = match hir[p].key { PropKey::Name(name) => name, + // `emitComputedPropertyName` PropKey::Computed(e) => { - return Some(cat!(b"[", self.cloned_expression_text(file, e)?, b"]")); + let expression = self.cloned_expression_text(file, e, OperatorPrecedence::Yield)?; + return Some(cat!(b"[", expression, b"]")); } PropKey::Private(_) | PropKey::None => return None, }; @@ -5121,13 +5568,6 @@ impl<'p, 's> Printer<'_, 'p, 's> { declaration: None, }); } - // A list with a variadic element that is not last cannot be printed. - if expanded - .split_last() - .is_some_and(|(_, before)| before.iter().any(|parameter| parameter.rest)) - { - return parameters.to_vec(); - } expanded } @@ -5194,22 +5634,23 @@ impl<'p, 's> Printer<'_, 'p, 's> { /// `NodeBuilder.SerializeReturnTypeForSignature`, in this context. fn serialize_return_type_for_signature(&mut self, signature: SigId) -> Node { - let (_, outer_scope) = self.enter_signature_scope(signature); + let (_, outer_scope) = self.enter_signature_scope(signature, None); let returned = self.return_type_node(signature, true); self.leave_scope(&outer_scope); returned } /// `signatureToSignatureDeclarationHelper`, as printed text, without the `;` of a member. - /// `name`, `is_optional`: those of a method. + /// `name`, `is_optional`: those of a method. `of`: the type that has `signature`. fn signature_to_text( &mut self, signature: SigId, kind: SignatureKind, name: &[u8], is_optional: bool, + of: Option, ) -> Vec { - let (head, returned) = self.signature_to_parts(signature, kind, name, is_optional); + let (head, returned) = self.signature_to_parts(signature, kind, name, is_optional, of); match kind { SignatureKind::SetAccessor => head, _ => cat!(head, returned.text), @@ -5223,8 +5664,9 @@ impl<'p, 's> Printer<'_, 'p, 's> { kind: SignatureKind, name: &[u8], is_optional: bool, + of: Option, ) -> (Vec, Node) { - let (expanded, outer_scope) = self.enter_signature_scope(signature); + let (expanded, outer_scope) = self.enter_signature_scope(signature, of); self.approximate_length += 3; let mut type_parameters = Vec::new(); let own_type_parameters = self.c.sig_type_params(signature).into_vec(); @@ -5235,8 +5677,21 @@ impl<'p, 's> Printer<'_, 'p, 's> { for parameter in own_type_parameters { type_parameters.push(self.type_parameter_declaration(parameter, &clones)); } - let mut parameters = Vec::with_capacity(expanded.len() + 1); - for parameter in &expanded { + // A list with a variadic element that is not last is not expanded. Only a symbol that + // `getExpandedParameters` creates has `CheckFlagsRestParameter`. + let has_leading_variadic = expanded.split_last().is_some_and(|(_, before)| { + let mut created = before + .iter() + .filter(|parameter| parameter.declaration.is_none()); + created.any(|parameter| parameter.rest) + }); + let listed = if has_leading_variadic { + self.signature_parameters(signature) + } else { + expanded + }; + let mut parameters = Vec::with_capacity(listed.len() + 1); + for parameter in &listed { parameters.push(self.parameter_text(parameter)); } if let Some((this, declared_by)) = self.c.sig_this_parameter(signature) { @@ -5274,27 +5729,37 @@ impl<'p, 's> Printer<'_, 'p, 's> { (head, returned) } + /// `signature.mapper`: that of the last `instantiateSignature`. `sig_decl` has the composition + /// of all of them. `of`: the type that has `signature`. + fn mapper_of_signature(&self, signature: SigId, of: Option) -> Option { + let (file, func, composed) = self.c.sig_decl(signature)?; + let mapper = match of.map(|of| self.c.data(of)) { + // `resolveAnonymousTypeMembers`: `instantiateSignatures(.., t.mapper)` + Some(TypeData::Synth(shape)) if shape.instantiation_target.is_some() => shape.mapper, + _ => match self.c.steps_of_sig_mapper(file, func, composed) { + Some((_, last)) => last, + None => composed, + }, + }; + self.c.is_instantiating(mapper).then_some(mapper) + } + /// `enterSignatureScope`: returns the `getExpandedParameters` of `signature`, and the state - /// needed to leave the scope. - fn enter_signature_scope(&mut self, signature: SigId) -> (Vec, OuterScope) { + /// needed to leave the scope. `of`: the type that has `signature`. + fn enter_signature_scope( + &mut self, + signature: SigId, + of: Option, + ) -> (Vec, OuterScope) { let saved_mapper = self.mapper; - if let Some((_, _, mapper)) = self.c.sig_decl(signature) - && self - .c - .types() - .mapping(mapper) - .iter() - .any(|pair| pair.0 != pair.1) - { + if let Some(mapper) = self.mapper_of_signature(signature, of) { self.mapper = mapper; } let declared = self.signature_parameters(signature); let expanded = self.expanded_parameters(&declared); let own_type_parameters = self.c.sig_type_params(signature).into_vec(); - let is_instantiated = self.c.sig_decl(signature).is_some_and(|declared| { - let mapping = self.c.types().mapping(declared.2); - mapping.iter().any(|pair| pair.0 != pair.1) - }); + let is_instantiated = (self.c.sig_decl(signature)) + .is_some_and(|declared| self.c.is_instantiating(declared.2)); let declarations_of = |parameters: &[Parameter]| -> Vec> { parameters.iter().map(|p| p.declaration).collect() }; @@ -5353,9 +5818,9 @@ impl<'p, 's> Printer<'_, 'p, 's> { } } - /// A function type or a constructor type. - fn signature_to_node(&mut self, signature: SigId, kind: SignatureKind) -> Node { - let (head, returned) = self.signature_to_parts(signature, kind, b"", false); + /// A function type or a constructor type: the only signature of `of`. + fn signature_to_node(&mut self, signature: SigId, kind: SignatureKind, of: TypeId) -> Node { + let (head, returned) = self.signature_to_parts(signature, kind, b"", false, Some(of)); Node::function(&head, returned) } diff --git a/src/sema/check/print_node_reuse.rs b/src/sema/check/print_node_reuse.rs index 5ecfbb6a6112..7a89ecd9080e 100644 --- a/src/sema/check/print_node_reuse.rs +++ b/src/sema/check/print_node_reuse.rs @@ -61,13 +61,8 @@ impl<'p> Printer<'_, 'p, '_> { self.type_to_node(this) } - /// `addPropertyToElementList`: the type `ty` of the property `prop` of `owner`. - pub(super) fn serialize_type_of_property( - &mut self, - owner: TypeId, - prop: &Prop, - ty: TypeId, - ) -> Node { + /// `addPropertyToElementList`: the type `ty` of the property `prop`. + pub(super) fn serialize_type_of_property(&mut self, prop: &Prop, ty: TypeId) -> Node { if let Some((file, declaration)) = self.value_declaration_of_property(prop) { // `t.symbol == symbol`: a symbol derived from the declared one (`getSpreadSymbol`, // `createSymbolWithType`) is not the symbol of its `unique symbol` type. @@ -78,7 +73,7 @@ impl<'p> Printer<'_, 'p, '_> { } // `symbol.Flags&SymbolFlagsOptional != 0 && ReverseMappedSymbolLinks.Has(symbol)` let is_optional_reverse_mapped = prop.flags.contains(PropFlags::OPTIONAL) - && matches!(self.c.data(owner), TypeData::ReverseMapped { .. }); + && matches!(prop.source, PropSource::ReverseMapped(..)); return self.serialize_type_for_declaration( file, declaration, @@ -104,16 +99,6 @@ impl<'p> Printer<'_, 'p, '_> { return None; } let pt = self.c.iso_pseudo_of_return(file, func); - // `getReturnTypeOfSignature`: a circular annotation resolves to `anyType`, which is not the - // annotated type. - let (p, key) = (self.c.p, (file, func)); - if matches!(pt, Pseudo::Direct(_)) - && ((p.fn_return_types.get(&self.c.task, &key)) - .is_some_and(|(_, is_circular)| is_circular) - || p.circular_returns.get(&self.c.task, &key).is_some()) - { - return None; - } let report_errors = !self.suppress_report_inference_fallback; if !self.pseudo_type_equivalent_to_type(file, &pt, returned, false, report_errors) { return None; @@ -169,11 +154,13 @@ impl<'p> Printer<'_, 'p, '_> { (file, variable @ Decl::Var(_)) => Some((file, self.c.hir(file).node(variable))), // Among assignment declarations, the first annotated one determines the type. (file, Decl::Expando(first) | Decl::ThisProperty(first)) => { - let (hir, list) = (self.c.hir(file), self.c.assignments_of_symbol(*symbol)); - let annotated = list - .iter() - .find(|&&e| hir.jsdoc_type(JsDocTypeOwner::Assign(e)).is_some()); - Some((file, self.c.hir(file).node(*annotated.unwrap_or(&first)))) + let list = self.c.assignments_of_symbol(*symbol); + let annotated = list.iter().copied().find(|&(of, e)| { + let annotation = self.c.hir(of).jsdoc_type(JsDocTypeOwner::Assign(e)); + annotation.is_some() + }); + let (file, declaration) = annotated.unwrap_or((file, first)); + Some((file, self.c.hir(file).node(declaration))) } _ => None, }, @@ -599,7 +586,7 @@ impl<'p> Printer<'_, 'p, '_> { } /// `Text()` of the `NumericLiteral` or `BigIntLiteral` `e`: what the printer emits for a clone. - fn text_of_number_literal(&self, file: FileId, e: ExprId) -> Vec { + pub(super) fn text_of_number_literal(&self, file: FileId, e: ExprId) -> Vec { let hir = self.c.hir(file); match hir[e].kind { ExprKind::BigInt(digits) => self @@ -644,12 +631,7 @@ impl<'p> Printer<'_, 'p, '_> { }; type_parameters.push(declaration); } - let mut this = None; - if function.this_ty(self.c.hir(file)).is_some() { - let node = self.reuse_type_node(file, function.this_ty(self.c.hir(file))); - this = Some(cat!(b"this: ", node.text)); - } - let parameters = self.pseudo_parameters_to_text(file, this, params); + let parameters = self.pseudo_parameters_to_text(file, params); let type_parameters = if type_parameters.is_empty() { Vec::new() } else { @@ -658,19 +640,13 @@ impl<'p> Printer<'_, 'p, '_> { cat!(type_parameters, b"(", parameters, b")") } - /// `pseudoParametersToNodeList`, as the printer emits it. `this`: a leading `this` parameter. - fn pseudo_parameters_to_text( - &mut self, - file: FileId, - this: Option>, - params: &[PseudoParam], - ) -> Vec { + /// `pseudoParametersToNodeList`, as the printer emits it. + fn pseudo_parameters_to_text(&mut self, file: FileId, params: &[PseudoParam]) -> Vec { // `setCommentRange` let has_comment_range = !self.c.files().options.remove_comments && self.enclosing_declaration.is_some_and(|it| it.file == file); let indent = self.indent.filter(|_| has_comment_range); - let mut parameters = Vec::with_capacity(params.len() + 1); - parameters.extend(this.map(|text| Element { range: None, text })); + let mut parameters = Vec::with_capacity(params.len()); for param in params { let loc = self.c.hir(file)[param.param].loc; parameters.push(Element { @@ -689,9 +665,14 @@ impl<'p> Printer<'_, 'p, '_> { let declaration = self.c.hir(file)[param.param]; self.track_parameter_declaration_name(file, param.param); let ty = self.pseudo_type_to_node(file, ¶m.ty); + // The name that the reparser gives the parameter of a `@this` tag is not in the source. + let name = if self.c.is_this_parameter(file, param.param) { + b"this".to_vec() + } else { + self.binding_name_text(file, declaration.pat) + }; cat! { - if declaration.flags.contains(Flags::REST) { &b"..."[..] } else { b"" }, - self.binding_name_text(file, declaration.pat), + if declaration.flags.contains(Flags::REST) { &b"..."[..] } else { b"" }, name, if param.is_optional { &b"?"[..] } else { b"" }, b": ", ty.text } } @@ -740,7 +721,7 @@ impl<'p> Printer<'_, 'p, '_> { let name = self.text(name); // `classifyPropertyName` let is_new_method = is_method && name == b"new"; - if !is_new_method && is_identifier(&name) { + if !is_new_method && is_identifier_text(&name) { return name; } let is_string_literal = matches!(first, Some(b'"' | b'\'')); @@ -821,7 +802,7 @@ impl<'p> Printer<'_, 'p, '_> { PseudoElementKind::Setter { param, .. } => { let name = self.pseudo_property_name(file, element.prop, false); let parameter = - self.pseudo_parameters_to_text(file, None, std::slice::from_ref(param)); + self.pseudo_parameters_to_text(file, std::slice::from_ref(param)); cat!(b"set ", name, b"(", parameter, b");") } PseudoElementKind::Getter { ty, .. } => { @@ -882,13 +863,19 @@ impl<'p> Printer<'_, 'p, '_> { } } - /// `reuseNode` for a type node. The outermost `ParenthesizedType` around `node` is that node. - pub(super) fn try_reuse_type_node(&mut self, file: FileId, node: TypeNodeId) -> Option { - let outermost = self.c.parenthesized_types_around(file, node, 0).last(); + /// `reuseNode` for a type node: the outermost `ParenthesizedType` around `node` that opens at + /// `floor` or later, `node` itself if there is none. 0 for an annotation. + pub(super) fn try_reuse_type_node( + &mut self, + file: FileId, + node: TypeNodeId, + floor: u32, + ) -> Option { + let outermost = (self.c.parenthesized_types_around(file, node, floor)).last(); let start = outermost.map_or_else(|| self.c.hir(file)[node].pos, |start| start as u32); - let existing = (start, self.c.end_of_type_node_from(file, node, 0)); + let existing = (start, self.c.end_of_type_node_from(file, node, floor)); let reused = self.try_reuse_existing_node_helper(file, existing, |printer| { - printer.visit_existing_type_node(file, node, 0) + printer.visit_existing_type_node(file, node, floor) })?; if self.c.hir(file).text.is_empty() { self.approximate_length += reused.text.len() + 1; @@ -901,7 +888,7 @@ impl<'p> Printer<'_, 'p, '_> { if node.is_none() { return Node::simple(b"any"); } - match self.try_reuse_type_node(file, node) { + match self.try_reuse_type_node(file, node, 0) { Some(reused) => reused, None => { self.report_inference_fallback(file, self.c.hir(file).node(node)); @@ -926,16 +913,14 @@ impl<'p> Printer<'_, 'p, '_> { if node.is_none() { return Some(Node::simple(b"any")); } - if self.depth >= MAXIMUM_DEPTH || self.c.is_stack_low() { + if self.c.is_stack_low() { return Some(self.elided_information_placeholder()); } - self.depth += 1; let recovery_scope = self.start_recovery_scope(); let hir = self.c.hir(file); let visited = self.emit_with_leading_comments(file, hir[node].pos, |printer| { printer.visit_existing_type_node_worker(file, node) }); - self.depth -= 1; let mut visited = match visited { Some(visited) if !self.had_error() => visited, _ if matches!(hir[node].kind, TypeNodeKind::Predicate { .. }) => { @@ -1164,7 +1149,7 @@ impl<'p> Printer<'_, 'p, '_> { let hir = self.c.hir(file); let pos = hir[node].pos; Some(match hir[node].kind { - TypeNodeKind::Error | TypeNodeKind::Heritage(_) => return None, + TypeNodeKind::Error | TypeNodeKind::Heritage { .. } => return None, TypeNodeKind::Keyword(keyword) => Node::simple(keyword.text()), TypeNodeKind::Ref { .. } => return self.try_visit_type_reference(file, node), TypeNodeKind::Typeof { .. } => return self.try_visit_type_query(file, node), @@ -1415,8 +1400,7 @@ impl<'p> Printer<'_, 'p, '_> { && !self.c.files().options.isolated_declarations && let PropKey::Computed(name) = hir[m].key && is_dynamic_name(hir, name) - && !(is_entity_name_expression(hir, name) - && self.c.member_name(file, hir[m].key).is_some()) + && !(self.c.is_late_bound(file, m) && is_entity_name_expression(hir, name)) { continue; } @@ -1516,6 +1500,14 @@ impl<'p> Printer<'_, 'p, '_> { }) } TypeNodeKind::Predicate { param, ty, asserts } => { + // `IsIdentifier(node.ParameterName)`. `visitDeclarationSubtree` leaves it as it is. + if param != known::this && !self.is_transformer { + let scope = self.c.bound(file).type_scope[node.idx()]; + let name = hir.node(node); + if self.track_existing_entity_name(file, name, scope, param, SymFlags::VALUE) { + self.mark_error(); + } + } let mut text = Vec::new(); if asserts { text.extend_from_slice(b"asserts "); @@ -1681,7 +1673,7 @@ impl<'p> Printer<'_, 'p, '_> { self.is_transformer = false; // `TryJSTypeNodeToTypeNode` let reused = match is_annotated { - true => self.try_reuse_type_node(file, annotation), + true => self.try_reuse_type_node(file, annotation, 0), false => None, }; let ty = match (reused, hir.function_of(node).some()) { @@ -1715,9 +1707,9 @@ impl<'p> Printer<'_, 'p, '_> { fn visit_parameter_declarations(&mut self, file: FileId, f: FnId) -> Option> { let function = self.c.hir(file)[f]; let mut parameters = Vec::with_capacity(function.params.len() + 1); - if function.this_ty(self.c.hir(file)).is_some() { - let this = - self.visit_existing_type_node(file, function.this_ty(self.c.hir(file)), 0)?; + if let Some(this) = function.this_param.some() { + let hir = self.c.hir(file); + let this = self.ensure_type(file, hir.node(this), hir[this].ty)?; parameters.push(cat!(b"this: ", this.text)); } let has_this = !parameters.is_empty(); @@ -1933,33 +1925,49 @@ impl<'p> Printer<'_, 'p, '_> { /// `trackExistingEntityName` for the name after `typeof` in `query`, which starts with `this`: /// whether the symbol of `getThisContainer` is accessible where the name is printed. A member - /// has no symbol: it is as accessible as its container (`getContainersOfSymbol`). + /// is in no table: it is as accessible as its container (`getContainersOfSymbol`), which for + /// a literal is the variable of `getVariableDeclarationOfObjectLiteral`. fn is_this_container_accessible(&mut self, file: FileId, query: TypeNodeId) -> bool { - let (hir, bound) = (self.c.hir(file), self.c.bound(file)); + let (hir, bound, files) = (self.c.hir(file), self.c.bound(file), self.c.files()); let TypeNodeKind::Typeof { expr, .. } = hir[query].kind else { return false; }; let scope = bound.type_scope[query.idx()]; - let this = first_identifier(hir, expr); - let symbol = match self.c.this_container(file, this) { - Some(Ok(f)) => match bound.fns[f.idx()].owner { - FnOwner::Stmt(_) => bound.fn_symbol[f.idx()], - FnOwner::Member(m) => match bound.member_owner[m.idx()] { - MemberOwner::Class(c) => bound.class_symbol[c.idx()], - MemberOwner::Interface(i) => bound.interface_symbol[i.idx()], - _ => SymbolId::NONE, - }, - _ => SymbolId::NONE, + let this = hir.node(first_identifier(hir, expr)); + let declared = |symbol: SymbolId| symbol.is_some().then(|| files.sym(file, symbol)); + let symbol = match hir.data(hir.get_this_container(this, false, false)) { + // A script has no symbol, and a module can be named by an `import` type. + NodeData::File => return true, + NodeData::Stmt(s) => match hir[s].kind { + StmtKind::Fn(f) => declared(bound.fn_symbol[f.idx()]), + StmtKind::Module(m) => declared(bound.module_symbol[m.idx()]), + StmtKind::Enum(e) => declared(bound.enum_symbol[e.idx()]), + _ => None, }, - Some(Err((c, _))) => bound.class_symbol[c.idx()], - _ => SymbolId::NONE, + // It has no symbol. + NodeData::Member(m) if hir[m].kind == MemberKind::StaticBlock => return true, + NodeData::Member(m) => match bound.member_owner[m.idx()] { + MemberOwner::Class(c) => declared(bound.class_symbol[c.idx()]), + MemberOwner::Interface(i) => declared(bound.interface_symbol[i.idx()]), + MemberOwner::TypeLiteral(literal) => { + let literal = Decl::TypeLiteral(literal); + self.c.variable_declaration_of_object_literal(file, literal) + } + MemberOwner::None => None, + }, + NodeData::Prop(p) => { + let literal = Decl::ObjectLiteral(bound.prop_owner[p.idx()]); + self.c.variable_declaration_of_object_literal(file, literal) + } + // The symbol of a function expression is in no table and has no parent. + _ => None, }; - symbol.is_some() && scope.is_some() && { - let symbol = self.c.files().sym(file, symbol); - let at = Enclosing::at_scope(file, scope); - self.c - .is_symbol_accessible_at(symbol, SymFlags::VALUE, false, at) - } + let Some(symbol) = symbol.filter(|_| scope.is_some()) else { + return false; + }; + let at = Enclosing::at_scope(file, scope); + self.c + .is_symbol_accessible_at(symbol, SymFlags::VALUE, false, at) } /// `tryVisitTypeReference` @@ -2077,6 +2085,7 @@ impl<'p> Printer<'_, 'p, '_> { ) -> bool { let files = self.c.files(); let here = (self.c.resolve(file, scope, first, meaning, false)).unwrap_or(None); + self.c.note_use_of_tracked_name(file, scope, first, meaning); // A type parameter is not resolved again. if here.is_some_and(|symbol| files.flags(symbol).contains(SymFlags::TYPE_PARAMETER)) { return false; @@ -2093,7 +2102,11 @@ impl<'p> Printer<'_, 'p, '_> { let there = match parameter { Some(&(_, Some(parameter))) => Some(parameter), Some(&(_, None)) => return here.is_some(), - None => (self.c.resolve(at.file, at.scope, first, meaning, false)).unwrap_or(None), + None => { + self.c + .note_use_of_tracked_name(at.file, at.scope, first, meaning); + (self.c.resolve(at.file, at.scope, first, meaning, false)).unwrap_or(None) + } }; let symbol = match (there, here) { (None, None) => return false, @@ -2169,6 +2182,26 @@ impl<'p> Printer<'_, 'p, '_> { } impl Checker<'_, '_> { + /// `isUse` of a `resolveName` of the node builder, which starts in `scope` of `file`. Nothing + /// reads `symbolReferenceLinks` once `checkSourceFile` has returned. + pub(super) fn note_use_of_tracked_name( + &mut self, + file: FileId, + scope: ScopeId, + name: Atom, + meaning: SymFlags, + ) { + let options = &self.files().options; + let used = (file, scope, name, meaning); + if (options.no_unused_locals || options.no_unused_parameters) + && scope.is_some() + && !self.is_type_checked + && !self.tracked_names.contains(&used) + { + self.tracked_names.push(used); + } + } + /// `canReuseExistingJSTypeNode`: false for a node that represents a different type in a JSDoc /// comment, and for a reference to the target of `ty` with too few type arguments. fn can_reuse_existing_js_type_node( diff --git a/src/sema/check/relate.rs b/src/sema/check/relate.rs index ae598ffd1e48..f563dd3dba96 100644 --- a/src/sema/check/relate.rs +++ b/src/sema/check/relate.rs @@ -245,6 +245,9 @@ pub(super) struct Relater { /// (`check_type_related_to_ex`), which must leave the cache as tsgo's run would find it. pub(super) caches_failures: bool, failed: FxHashSet, + /// `compareTypes` of `compareSignaturesRelated` is `compareTypesAssignable`: each two types are + /// a check of their own, and nothing else of this relater is used. + compares_types_assignable: bool, /// `errorNode`. An end of `0` means the end of the token at the start. This field and the /// following ones are read only under `reportErrors`. pub(super) error_node: Place, @@ -278,6 +281,7 @@ impl Relater { cycles, caches_failures: false, failed: FxHashSet::default(), + compares_types_assignable: false, error_node: (FileId(0), 0, 0), head_message: None, error_chain: None, @@ -448,7 +452,7 @@ pub(super) fn is_object_literal_kind(data: &TypeData) -> bool { origin: Origin::ObjectLiteral(..), .. } => true, - TypeData::Synth(shape) => shape.literal.is_of_expression(), + TypeData::Synth(shape) => shape.literal.is_of_expression() || shape.literal.is_of_pattern(), _ => false, } } @@ -698,33 +702,35 @@ impl<'p, 's> Checker<'p, 's> { if matches!(ty, TypeId::EMPTY_OBJECT | TypeId::EMPTY_TYPE_LITERAL) { return true; } - match self.data(ty) { - // `newAnonymousType` takes the members. `getTypeWithSyntheticDefaultImportType` gives - // its result the symbol of a type literal without members. - TypeData::Synth(shape) => { - shape.literal == Literalness::SyntheticDefault || self.is_empty_resolved_type(ty) + // `newAnonymousType` takes the members: `checkObjectLiteral`, `getSpreadType`, + // `getRestType` and `getWidenedTypeOfObjectLiteral` call it. `instantiateAnonymousType` + // does not. + let mapper = match self.data(ty) { + // `getTypeWithSyntheticDefaultImportType` gives its result the symbol of a type literal + // without members. + TypeData::Synth(shape) if shape.literal == Literalness::SyntheticDefault => { + return true; } - // `checkObjectLiteral` and `getWidenedTypeOfObjectLiteral` call `newAnonymousType`, - // `instantiateAnonymousType` does not. + TypeData::Synth(shape) => Some(shape.mapper), TypeData::Anon { origin: Origin::ObjectLiteral(..) | Origin::WidenedLiteral(..), mapper, - } if self.types().mapping(*mapper).iter().all(|p| p.0 == p.1) => { - self.is_empty_resolved_type(ty) - } + } => Some(*mapper), // `ObjectFlagsMapped`, without `ObjectFlagsAnonymous`. TypeData::Anon { origin: Origin::Mapped(..), .. - } => false, + } => return false, // A type literal that has an `Origin` has members in its symbol. - TypeData::Anon { .. } | TypeData::ReverseMapped { .. } => { - match self.resolved_members(ty) { - Some(members) => Self::has_no_members(members.shape()), - None => self.has_no_members_in_place(ty), - } - } - _ => false, + TypeData::Anon { .. } | TypeData::ReverseMapped { .. } => None, + _ => return false, + }; + if mapper.is_some_and(|mapper| !self.is_instantiating(mapper)) { + return self.is_empty_resolved_type(ty); + } + match self.resolved_members(ty) { + Some(members) => Self::has_no_members(members.shape()), + None => self.has_no_members_in_place(ty), } } @@ -2017,11 +2023,10 @@ impl<'p, 's> Checker<'p, 's> { /// `getNameTypeFromMappedType` pub(super) fn mapped_name_type(&mut self, t: TypeId) -> Option { let (file, node, _) = self.mapped_origin(t)?; - let name = self.mapped_decl(file, node).name_ty; - if name.is_none() { + if self.mapped_decl(file, node).name_ty.is_none() { return None; } - let declared = self.type_from_node(file, name); + let declared = self.declared_name_type_of_mapped(file, node); let mapper = self.mapped_mapper(t); Some(self.instantiate(declared, mapper)) } @@ -2819,7 +2824,9 @@ impl<'p, 's> Checker<'p, 's> { { return false; } + // `isSignatureAssignableTo` let mut r = Relater::new(Relation::Assignable, self.cycles); + r.compares_types_assignable = true; self.compare_signatures_related::( &mut r, source, @@ -3818,9 +3825,7 @@ impl<'p, 's> Checker<'p, 's> { } else { self.structured_type_related_to::(r, source, sd, target, td, state) }; - // With reporting the result can differ (`relate_variances`), so it is not cached. - let ended = self.end_scope(scope).ok(); - let stored = ended.filter(|_| !REPORT); + let stored = self.end_scope(scope).ok(); let propagating = self.reliability; self.reliability |= save_reliability; if recursion & REC_SOURCE != 0 { @@ -3840,6 +3845,7 @@ impl<'p, 's> Checker<'p, 's> { propagating, result == Ternary::TRUE || result == Ternary::MAYBE, stored, + REPORT, ); } } else { @@ -3851,14 +3857,14 @@ impl<'p, 's> Checker<'p, 's> { if !is_cut_short { r.failed.insert(key); } - } else if let Some(stored) = ended + } else if let Some(stored) = stored && !is_cut_short && cached.is_none() { self.insert_relation(key, FAILED | propagating, stored); } r.relation_count -= 1; - self.reset_maybe_stack(r, maybe_start, propagating, false, stored); + self.reset_maybe_stack(r, maybe_start, propagating, false, stored, REPORT); } result } @@ -3894,11 +3900,16 @@ impl<'p, 's> Checker<'p, 's> { let (key, _) = self.relation_key(source, target, relation, STATE_NONE, false); let scope = self.begin_scope(); if let Ok(stored) = self.end_scope_as(scope, false) { - if self.p.relations.get(&self.task, &key).is_none() { - self.insert_relation(key, FAILED | kind, stored); - } else { - (self.p.relations).rewrite(&self.task, key, FAILED | kind, stored); - } + self.set_relation(key, FAILED | kind, stored); + } + } + + /// `relation.set(key, entry)` + fn set_relation(&mut self, key: Key, entry: u8, stored: Stored) { + if self.p.relations.get(&self.task, &key).is_none() { + self.insert_relation(key, entry, stored); + } else { + (self.p.relations).rewrite(&self.task, key, entry, stored); } } @@ -3914,7 +3925,8 @@ impl<'p, 's> Checker<'p, 's> { (16_000_000 - self.relation_sizes[relation as usize]) / 8 } - /// `resetMaybeStack` + /// `resetMaybeStack`. `report_errors`: a comparison that elaborates begins at a key whose entry + /// is a failure, which an overflow may have cut off. fn reset_maybe_stack( &mut self, r: &mut Relater, @@ -3922,6 +3934,7 @@ impl<'p, 's> Checker<'p, 's> { propagating: u8, mark_all_as_succeeded: bool, stored: Option, + report_errors: bool, ) { while r.maybe_keys.len() > maybe_start { let Some(key) = r.maybe_keys.pop() else { @@ -3929,8 +3942,12 @@ impl<'p, 's> Checker<'p, 's> { }; r.maybe_keys_set.remove(&key); if mark_all_as_succeeded { - if let Some(stored) = stored { - self.insert_relation(key, SUCCEEDED | propagating, stored); + match stored { + Some(stored) if report_errors => { + self.set_relation(key, SUCCEEDED | propagating, stored); + } + Some(stored) => self.insert_relation(key, SUCCEEDED | propagating, stored), + None => {} } r.relation_count -= 1; } @@ -6776,6 +6793,22 @@ impl<'p, 's> Checker<'p, 's> { } } + /// `compareTypes` of `compareSignaturesRelated`: `isRelatedToEx` of `r`, as `signatureRelatedTo` + /// passes it, or `compareTypesAssignable`. + #[inline] + fn compare_types_related( + &mut self, + r: &mut Relater, + source: TypeId, + target: TypeId, + state: u8, + ) -> Ternary { + if r.compares_types_assignable { + return Ternary::of(self.is_assignable(source, target)); + } + self.is_related_to_ex::(r, source, target, REC_BOTH, state) + } + /// `compareSignaturesRelated`. `as_passed`: the two signatures before type parameter erasure. pub(super) fn compare_signatures_related( &mut self, @@ -6835,7 +6868,7 @@ impl<'p, 's> Checker<'p, 's> { } signature_targets.0 = Some(Some(source)); source = self.instantiate_sig_in_context(source, target, true, &mut |c, s, t| { - c.is_related_to_ex::(r, s, t, REC_BOTH, state) != Ternary::FALSE + c.compare_types_related::(r, s, t, state) != Ternary::FALSE }); } let sp = self.sig_params(source); @@ -6864,11 +6897,10 @@ impl<'p, 's> Checker<'p, 's> { let mut related = if strict_variance { Ternary::FALSE } else { - self.is_related_to_ex::(r, source_this, target_this, REC_BOTH, state) + self.compare_types_related::(r, source_this, target_this, state) }; if !related.holds() { - related = - self.is_related_to_ex::(r, target_this, source_this, REC_BOTH, state); + related = self.compare_types_related::(r, target_this, source_this, state); } if !related.holds() { if REPORT { @@ -6958,16 +6990,15 @@ impl<'p, 's> Checker<'p, 's> { } None => { let mut related = if check_mode & CALLBACK == 0 && !strict_variance { - self.is_related_to_ex::(r, source_type, target_type, REC_BOTH, state) + self.compare_types_related::(r, source_type, target_type, state) } else { Ternary::FALSE }; if !related.holds() { - related = self.is_related_to_ex::( + related = self.compare_types_related::( r, target_type, source_type, - REC_BOTH, state, ); } @@ -6980,7 +7011,7 @@ impl<'p, 's> Checker<'p, 's> { && i >= self.min_argument_count(&sp) && i < self.min_argument_count(&tp) && self - .is_related_to_ex::(r, source_type, target_type, REC_BOTH, state) + .compare_types_related::(r, source_type, target_type, state) .holds() { related = Ternary::FALSE; @@ -7024,18 +7055,13 @@ impl<'p, 's> Checker<'p, 's> { // The return types of callbacks are compared bivariantly too, or `interface Foo { // add(cb: () => T): void }` would not be covariant in `T`. let mut related = if check_mode & BIVARIANT_CALLBACK != 0 { - self.is_related_to_ex::(r, target_return, source_return, REC_BOTH, state) + self.compare_types_related::(r, target_return, source_return, state) } else { Ternary::FALSE }; if !related.holds() { - related = self.is_related_to_ex::( - r, - source_return, - target_return, - REC_BOTH, - state, - ); + related = + self.compare_types_related::(r, source_return, target_return, state); } result &= related; // `incompatibleErrorReporter` @@ -7075,7 +7101,7 @@ impl<'p, 's> Checker<'p, 's> { } else { related = match (actual.ty, expected.ty) { (a, b) if a == b => Ternary::TRUE, - (Some(a), Some(b)) => self.is_related_to_ex::(r, a, b, REC_BOTH, state), + (Some(a), Some(b)) => self.compare_types_related::(r, a, b, state), _ => Ternary::FALSE, }; } diff --git a/src/sema/check/shape.rs b/src/sema/check/shape.rs index ab8bc6ae5c9b..801011cd614d 100644 --- a/src/sema/check/shape.rs +++ b/src/sema/check/shape.rs @@ -298,7 +298,9 @@ pub(super) enum IgnoreReturnTypes { /// What `get_spread_symbol` is told besides the property. #[derive(Copy, Clone)] pub(super) struct SpreadSymbolOptions { - /// `has_type_variables` of the type that has the property. + /// The type that has the property. + pub(super) owner: TypeId, + /// `has_type_variables` of that. pub(super) owner_is_generic: bool, /// `readonly` of `getSpreadSymbol`. pub(super) readonly: bool, @@ -664,6 +666,18 @@ impl<'p, 's> Checker<'p, 's> { key: TypeId, build: impl FnOnce(&mut Self) -> Shape<'s>, meanwhile: impl FnOnce(&mut Self) -> Shape<'s>, + ) -> Built<'p> { + self.shape_memo_bound(MemberBinding::Late, key, build, meanwhile) + } + + /// `binding`: `MemberBinding::Early` where `build` resolves the members from `earlySymbols` and + /// nothing assigns them again, see `gets_early_symbols_for_good`. + fn shape_memo_bound( + &mut self, + binding: MemberBinding, + key: TypeId, + build: impl FnOnce(&mut Self) -> Shape<'s>, + meanwhile: impl FnOnce(&mut Self) -> Shape<'s>, ) -> Built<'p> { if let Some(kept) = self.p.shapes.handle(&self.task, &key) { return Built { @@ -701,6 +715,17 @@ impl<'p, 's> Checker<'p, 's> { } return self.provisional_shape(shape); } + let mut resolved_before = self.members_resolved_before_base_types.iter(); + if let Some(&(_, resolved, _)) = resolved_before.find(|it| it.0 == key) + && let TypeData::Ref { target, .. } = *self.data(key) + && self.stack[self.resolution_start..].contains(&Query::Bases(target)) + { + self.note_members_in_place(); + return Built { + resolved, + kept: None, + }; + } // Nor is it one while the base types are being resolved: `resolveStructuredTypeMembers` has // no guard, and resolves the members again with the base types that there are so far. if let TypeData::Ref { target, .. } = *self.data(key) @@ -727,7 +752,9 @@ impl<'p, 's> Checker<'p, 's> { } // Nor is it one where the declared members are in place (`ObjectFlagsUnresolvedMembers`), // or the early-bound ones. - if self.inheriting.contains(&key) || self.is_late_binding(key) { + if self.inheriting.contains(&key) + || binding == MemberBinding::Late && self.is_late_binding(key) + { self.note_members_in_place(); let shape = meanwhile(self); return self.provisional_shape(shape); @@ -777,6 +804,12 @@ impl<'p, 's> Checker<'p, 's> { let built = self.provisional_shape(shape); let raw = std::ptr::from_ref(built.resolved) as usize as u64; self.cache_provisionally(Query::Shape(key), raw, open); + if let TypeData::Ref { target, .. } = *self.data(key) + && let Some(at) = (self.base_types_so_far.iter()).rposition(|it| it.0 == target) + { + self.members_resolved_before_base_types + .push((key, built.resolved, at)); + } built } } @@ -807,6 +840,33 @@ impl<'p, 's> Checker<'p, 's> { }) } + /// A request in the meantime, see `is_late_binding`, assigns the early-bound symbols of one side + /// of `container`. The call of `resolveDeclaredMembers` or `resolveAnonymousTypeMembers` that + /// has asked for the names assigns the members again once they are bound. `getLateBoundSymbol` + /// asks by itself: see `early_bound_for_good`. + fn note_members_from_early_symbols(&mut self, container: Sym, is_static: bool) { + let side = (self.files().canonical(container), is_static); + if self.late_binding_by_symbol.contains(&side) { + self.early_bound_for_good.insert(side); + } + } + + /// `binding`, or `MemberBinding::Early` for a side that is `early_bound_for_good`. + #[inline] + fn binding_of_side( + &self, + container: Sym, + is_static: bool, + binding: MemberBinding, + ) -> MemberBinding { + if !self.early_bound_for_good.is_empty() + && (self.early_bound_for_good).contains(&(self.files().canonical(container), is_static)) + { + return MemberBinding::Early; + } + binding + } + /// `getMembersOfSymbol(sym)` or `getExportsOfSymbol(sym)`, which `resolveDeclaredMembers` and /// `resolveAnonymousTypeMembers` begin with. The caller reads the computed names once more, and /// pops `late_binding` after that. `false`, only for the members: there is nothing to pop, see @@ -965,6 +1025,25 @@ impl<'p, 's> Checker<'p, 's> { callers.peek().is_some() && callers.all(|it| it.resolving != Some(ty)) } + /// Whether `resolveObjectTypeMembers` of `ty`, a reference to `target`, finds `earlySymbols` in + /// the links of `target`, it is `resolveDeclaredMembers` that has asked for the names, and no + /// call for `ty` further out assigns its members once more. `declaredMembers` is assigned + /// again, so `ty`, and no other reference, stays without the late-bound members. + fn gets_early_symbols_for_good(&self, target: Sym, ty: TypeId) -> bool { + let mut is_asked_by_declared_members = false; + for caller in &self.declared_members_in_progress { + if caller.symbol == target { + if caller.resolving == Some(ty) { + return false; + } + is_asked_by_declared_members = true; + } + } + is_asked_by_declared_members + && self.is_late_binding(ty) + && self.files().has_members_table(target) + } + /// `members` for a type with no cached entry. fn members_on_cache_miss(&mut self, ty: TypeId) -> Option> { let scope = self.begin_scope(); @@ -1030,6 +1109,10 @@ impl<'p, 's> Checker<'p, 's> { ); pairs.push((self.intern(TypeData::ThisParam(target)), this)); let mapper = self.types().mapper(pairs); + let binding = match self.gets_early_symbols_for_good(target, ty) { + true => MemberBinding::Early, + false => MemberBinding::Late, + }; // All instantiations share the shape of the declared type, unless their base types // depend on the type arguments, or on the members of the type: in `interface D // extends M`, `D` can be left without the members of `M`, and `D` with a @@ -1043,7 +1126,9 @@ impl<'p, 's> Checker<'p, 's> { .is_some()) { (ty, mapper) - } else if self.gets_no_declared_index_infos(target, ty) { + } else if binding == MemberBinding::Early + || self.gets_no_declared_index_infos(target, ty) + { // The declared type is the key of the shape that the others share: its own // is stored for `paddedTypeArguments`. let own = if declared == ty { @@ -1057,13 +1142,14 @@ impl<'p, 's> Checker<'p, 's> { }; // `getResolvedMembersOrExportsOfSymbol`: while the late-bound names are being // resolved, the members with literal names are available. - let mut resolved = self.shape_memo_or( + let mut resolved = self.shape_memo_bound( + binding, key, |c| { if are_provisional && key == ty { c.mark_tainted_from(c.frames.len() - 1); } - let (binding, bases) = (MemberBinding::Late, BaseMembers::Inherited); + let bases = BaseMembers::Inherited; c.build_declared_shape(target, under, binding, bases, Some(key), Some(ty)) }, |c| { @@ -1073,6 +1159,9 @@ impl<'p, 's> Checker<'p, 's> { if !is_bound && !c.files().has_members_table(target) { return c.resolve_members_from_nil_links(ty, target, under); } + if !is_bound { + c.note_members_from_early_symbols(target, false); + } let (binding, bases) = if is_bound && c.inheriting.contains(&key) { (MemberBinding::Late, BaseMembers::Omitted) } else if is_bound && c.base_types_so_far.iter().any(|it| it.0 == target) { @@ -1087,7 +1176,14 @@ impl<'p, 's> Checker<'p, 's> { if are_provisional { resolved.kept = None; } - Some((resolved, mapper)) + // A shape of its own is instantiated. Its inherited members are those of the + // instantiated base types, in which a type parameter of `target` comes from `args`. + let outer = if under == mapper { + MapperId::IDENTITY + } else { + mapper + }; + Some((resolved, outer)) } TypeData::Anon { origin, mapper } => { let (origin, mapper) = (*origin, *mapper); @@ -1144,7 +1240,8 @@ impl<'p, 's> Checker<'p, 's> { } } if let [(file, func)] = decls[..] { - shape = c.with_expandos(shape, file, c.bound(file).fn_symbol[func.idx()]); + let symbol = c.bound(file).symbol_of_function(c.hir(file), func); + shape = c.with_expandos(shape, file, symbol); } shape }); @@ -1286,25 +1383,24 @@ impl<'p, 's> Checker<'p, 's> { // ───────────────────────────── building ───────────────────────────── - fn member_flags(member: &Member) -> PropFlags { + /// `member`: the first declaration of a symbol that has `symbol_flags`. `modifiers`: + /// `getDeclarationModifierFlagsFromSymbol`. + fn member_flags(member: &Member, modifiers: Flags, symbol_flags: SymFlags) -> PropFlags { let mut flags = PropFlags::empty(); if member.flags.contains(Flags::OPTIONAL) { flags |= PropFlags::OPTIONAL; } // `isReadonlySymbol`: the modifier counts on a `SymbolFlagsProperty` only. - if member.flags.contains(Flags::READONLY) - && member.kind == MemberKind::Property - && !member.flags.contains(Flags::ACCESSOR) - { + if modifiers.contains(Flags::READONLY) && symbol_flags.contains(SymFlags::PROPERTY) { flags |= PropFlags::READONLY; } - if member.flags.contains(Flags::PRIVATE) { + if modifiers.contains(Flags::PRIVATE) { flags |= PropFlags::PRIVATE; } - if member.flags.contains(Flags::PROTECTED) { + if modifiers.contains(Flags::PROTECTED) { flags |= PropFlags::PROTECTED; } - if member.flags.contains(Flags::ABSTRACT) { + if modifiers.contains(Flags::ABSTRACT) { flags |= PropFlags::ABSTRACT; } match member.kind { @@ -1463,7 +1559,10 @@ impl<'p, 's> Checker<'p, 's> { if (has_static_side && member.flags.contains(Flags::STATIC)) != want_static { continue; } - if early && matches!(member.key, PropKey::Computed(e) if is_dynamic_name(hir, e)) { + let is_dynamic = matches!(member.key, PropKey::Computed(e) if is_dynamic_name(hir, e)); + // `getResolvedMembersOrExportsOfSymbol`: `isStatic == HasStaticModifier(member)`, + // whatever declares the member. + if is_dynamic && (early || member.flags.contains(Flags::STATIC) != want_static) { continue; } // `getDeclarationName`: a private name outside every class is `InternalSymbolNameMissing`, and `declareSymbolEx` adds @@ -1491,9 +1590,7 @@ impl<'p, 's> Checker<'p, 's> { }; continue; }; - if matches!(member.key, PropKey::Computed(e) if is_dynamic_name(hir, e)) - && self.is_late_bound_by_another_call(file, m) - { + if is_dynamic && self.is_late_bound_by_another_call(file, m) { continue; } match groups.iter_mut().find(|g| g.0 == name) { @@ -1733,17 +1830,18 @@ impl<'p, 's> Checker<'p, 's> { symbol_flags: SymFlags, ) -> PropFlags { let kind = |&(f, m): &(FileId, MemberId)| self.hir(f)[m].kind; - // `getDeclarationModifierFlagsFromSymbol`: the first declaration determines them, except - // that a getter takes precedence over a setter. - let (file, says) = match kind(&list[0]) { - MemberKind::Setter => list + // `getDeclarationModifierFlagsFromSymbol`: the getter determines them, else + // `ValueDeclaration`. + let (file, says) = match symbol_flags.contains(SymFlags::GET_ACCESSOR) { + true => list .iter() .copied() .find(|d| kind(d) == MemberKind::Getter) .unwrap_or(list[0]), - _ => list[0], + false => list[0], }; - let mut flags = Self::member_flags(&self.hir(file)[says]); + let (first, modifiers) = (&self.hir(list[0].0)[list[0].1], self.hir(file)[says].flags); + let mut flags = Self::member_flags(first, modifiers, symbol_flags); // Only in a class is anything private or protected: elsewhere the modifier is an error and // has no effect. if self.is_declared_outside_classes(file, says) { @@ -1911,19 +2009,17 @@ impl<'p, 's> Checker<'p, 's> { } for prop in &b.shape.props { let is_symbol = self.atoms().is_symbol_name(prop.name); - let is_numeric = self.is_numeric_name(prop.name); - if !(has_computed[0] && !is_symbol - || has_computed[1] && is_numeric - || has_computed[2] && is_symbol) - { - continue; - } - let value = self.type_of_prop(prop, MapperId::IDENTITY); - // `isSymbolWithComputedName`. `["a"]` is stored as a plain name. + // `symbol.Declarations[0]` let first = match prop.source { PropSource::Symbol(sym) => self.declarations_of_property(sym).first().copied(), _ => None, }; + let is_numeric = has_computed[1] && self.is_symbol_with_numeric_name(prop.name, first); + if !(has_computed[0] && !is_symbol || is_numeric || has_computed[2] && is_symbol) { + continue; + } + let value = self.type_of_prop(prop, MapperId::IDENTITY); + // `isSymbolWithComputedName`. `["a"]` is stored as a plain name. let component = match first { Some((file, Decl::Member(m))) => { let hir = self.hir(file); @@ -1954,6 +2050,23 @@ impl<'p, 's> Checker<'p, 's> { } } + /// `isSymbolWithNumericName` for a symbol called `name` whose `Declarations[0]` is `first`. + fn is_symbol_with_numeric_name(&mut self, name: Atom, first: Option<(FileId, Decl)>) -> bool { + if self.is_numeric_name(name) { + return true; + } + // `isNumericName`: the text of a name that is not computed is the name of the symbol. + let Some((file, Decl::Member(m))) = first else { + return false; + }; + let PropKey::Computed(e) = self.hir(file)[m].key else { + return false; + }; + // `isNumericComputedName` + let ty = self.check_computed_property_name(file, e); + self.is_assignable_to_kind(ty, Self::is_number_like, TypeId::NUMBER, false) + } + /// `#x`: mangled for the class that declares it (`rename_private_names`), or unmangled where no /// enclosing class declares it. pub(super) fn is_private_name(&self, name: Atom) -> bool { @@ -2090,6 +2203,17 @@ impl<'p, 's> Checker<'p, 's> { has_this_type } + /// `thisArgument` of `getTypeWithThisArgument(base, t.thisType)`, where `t` is the declared type + /// of `sym`: without a `thisType` it is that of the target of `base`. + pub(super) fn this_argument_for_base_type(&mut self, sym: Sym, base: TypeId) -> TypeId { + let has_this_type = self.has_this_type(sym); + let owner = match *self.data(base) { + TypeData::Ref { target, .. } if !has_this_type => target, + _ => sym, + }; + self.intern(TypeData::ThisParam(owner)) + } + /// `isThislessInterface` fn is_thisless_interface(&mut self, sym: Sym) -> bool { for (file, decl) in self.files().decls(sym) { @@ -2167,6 +2291,21 @@ impl<'p, 's> Checker<'p, 's> { self.members(ty) } + /// `resolveStructuredTypeMembers(apparent)`, where `apparent` is `getApparentType(ty)`. That + /// gives a base constraint that is a reference the type variable `ty` as its `this` argument, + /// for which a tuple has no slot. No other apparent type gets one. + fn members_of_apparent_type(&mut self, ty: TypeId, apparent: TypeId) -> Option> { + let is_tuple = |c: &Self, t: TypeId| matches!(c.data(t), TypeData::Tuple { .. }); + if self.is_deferred(ty) && is_tuple(self, apparent) { + let constraint = self.base_constraint(ty); + if is_tuple(self, constraint) { + let this_argument = ty; + return self.members_with_this(apparent, this_argument); + } + } + self.members(apparent) + } + /// The members `resolveObjectTypeMembers` inherits from one base type. fn inherit(&mut self, b: &mut Builder<'s>, base: TypeId, this: Option<(Sym, TypeId)>) { // `anyBaseTypeIndexInfo` @@ -2238,34 +2377,33 @@ impl<'p, 's> Checker<'p, 's> { /// Whether "the members of a base type, instantiated" are not "the members of the instantiated /// base type" for the class or interface `sym`: a base type is a type parameter - /// (`isValidBaseType`), or an instantiation of such a class or interface with a generic type - /// argument. + /// (`isValidBaseType`), a generic intersection, of which `getReducedType` can make `never`, a + /// tuple with a `...T` (`createNormalizedTupleType`), or an instantiation of such a class or + /// interface with a generic type argument. fn inherits_from_type_arguments(&mut self, sym: Sym) -> bool { for &base in self.base_types(sym).iter() { - let parts: &[TypeId] = match self.data(base) { - TypeData::Intersection(parts) => &parts[..], - _ => std::slice::from_ref(&base), - }; - for &part in parts { - let is_keyed_by_arguments = match *self.data(part) { - TypeData::TypeParam(..) => true, - TypeData::Ref { target, .. } => { - target != sym - && self.has_type_variables(part) - && self.inherits_from_type_arguments(target) - } - _ => false, - }; - if is_keyed_by_arguments { - return true; + let is_keyed_by_arguments = match self.data(base) { + TypeData::TypeParam(..) => true, + TypeData::Intersection(_) => self.has_type_variables(base), + TypeData::Tuple { flags, .. } => { + flags.iter().any(|it| it.contains(ElemFlags::VARIADIC)) } + &TypeData::Ref { target, .. } => { + target != sym + && self.has_type_variables(base) + && self.inherits_from_type_arguments(target) + } + _ => false, + }; + if is_keyed_by_arguments { + return true; } } false } - /// The instance shape of a class or an interface, in terms of its own type parameters. `under`: - /// the mapper applied to them in the base types. `in_place`: the key the shape is stored + /// The instance shape of a class or an interface, with its own type parameters instantiated by + /// `under` (`mapper` of `resolveObjectTypeMembers`). `in_place`: the key the shape is stored /// under, see `inheriting`. `resolving`: `t` of `resolveObjectTypeMembers`, `None` for /// `resolveDeclaredMembers` alone. fn build_declared_shape( @@ -2278,11 +2416,17 @@ impl<'p, 's> Checker<'p, 's> { resolving: Option, ) -> Shape<'s> { let mut b = Builder::new_in(self.arena); - b.declaring = Some(Declaring { + let declaring = Declaring { symbol: sym, resolving, - }); - let reads_names = binding == MemberBinding::Late && self.begin_late_binding(sym, false); + }; + b.declaring = Some(declaring); + let binding = self.binding_of_side(sym, false, binding); + let is_late = binding == MemberBinding::Late; + if is_late { + self.declared_members_in_progress.push(declaring); + } + let reads_names = is_late && self.begin_late_binding(sym, false); for (file, decl) in self.files().decls(sym) { let Some(members) = decl.members_of_class_or_interface(self.hir(file)) else { continue; @@ -2298,15 +2442,36 @@ impl<'p, 's> Checker<'p, 's> { if reads_names { self.late_binding.pop(); } + if is_late { + self.declared_members_in_progress.pop(); + } self.add_index_signatures_of_computed_names(&mut b); - let this = self.intern(TypeData::ThisParam(sym)); + // `thisArgument`: `resolveClassOrInterfaceMembers` has none. + let mut this = self + .has_this_type(sym) + .then(|| (sym, self.intern(TypeData::ThisParam(sym)))); + if under != MapperId::IDENTITY { + // `instantiateSymbolTable`, `instantiateSignatures`, `instantiateIndexInfos` + for prop in &mut b.shape.props { + self.instantiate_prop(prop, under); + } + for sig in (b.shape.call.iter_mut()).chain(b.shape.construct.iter_mut()) { + *sig = self.instantiate_sig(*sig, under); + } + for info in &mut b.shape.index { + info.value = self.instantiate(info.value, under); + } + if let Some((_, this_argument)) = &mut this { + *this_argument = self.instantiate(*this_argument, under); + } + } let bases = self.base_types(sym); let own = b.shape.props.len(); let inherits = base_members == BaseMembers::Inherited; self.inheriting.extend(in_place); for base in bases.iter().copied().filter(|_| inherits) { let base = self.instantiate(base, under); - self.inherit(&mut b, base, Some((sym, this))); + self.inherit(&mut b, base, this); } if in_place.is_some() { self.inheriting.pop(); @@ -2458,11 +2623,8 @@ impl<'p, 's> Checker<'p, 's> { let holds = self.leave(Query::BaseConstructor(class)).is_ok(); if self.left_a_cycle { let stored = (self.end_scope_as(scope, false)).unwrap_or_else(|_| self.cycle_result()); - // `GetErrorRangeForNode`: the name, or the first token of a class expression without one. - let declaration = &self.hir(file)[c]; - let start = declaration.name_pos; - let at = (file, start, self.end_of_token_at(file, start)); - let err = self.new_diagnostic(at, 2506, &[Arg::Sym(class)]); + let (start, end) = self.error_range_of_class(file, c); + let err = self.new_diagnostic((file, start, end), 2506, &[Arg::Sym(class)]); self.add_diagnostic_of(Some(Query::BaseConstructor(class)), err); let error = TypeId::ERROR; return self @@ -2635,8 +2797,7 @@ impl<'p, 's> Checker<'p, 's> { // `extends` clause. if let Some((file, c)) = self.extending_declaration(sym) { let base = self.base_instance_type(sym, file, c); - let extending = (file, Decl::Class(c)); - let valid = self.as_base_type(base, extending, |checker, reduced, unreduced| { + let valid = self.as_base_type(base, |checker, reduced, unreduced| { let Some(at) = checker.place_to_report_base_at(file, c) else { return; }; @@ -2663,12 +2824,12 @@ impl<'p, 's> Checker<'p, 's> { // skipped. if matches!( hir[node].kind, - TypeNodeKind::Error | TypeNodeKind::Heritage(_) + TypeNodeKind::Error | TypeNodeKind::Heritage { .. } ) { continue; } let base = self.type_from_node(file, node); - let valid = self.as_base_type(base, (file, decl), |checker, _, _| { + let valid = self.as_base_type(base, |checker, _, _| { let at = (file, hir[node].pos, checker.end_of_type_node(file, node)); checker.error_at(at, 2312, &[]); }); @@ -2683,6 +2844,9 @@ impl<'p, 's> Checker<'p, 's> { let left = self.leave(Query::Bases(sym)); let in_cycle = self.left_a_cycle; debug_assert_eq!(self.base_types_so_far.len(), so_far + 1); + // `t.objectFlags &^= ObjectFlagsMembersResolved` + self.members_resolved_before_base_types + .retain(|it| it.2 < so_far); let bases = self .base_types_so_far .pop() @@ -2709,7 +2873,8 @@ impl<'p, 's> Checker<'p, 's> { self.bound(file).class_owner[c.idx()], crate::bind::ClassOwner::Stmt(_) ), - _ => true, + Decl::Interface(_) => true, + _ => false, }; if is_declaration && let Some(err) = self.circular_base_type(sym, file, decl) { self.add_diagnostic_of(Some(Query::Bases(sym)), err); @@ -2785,6 +2950,17 @@ impl<'p, 's> Checker<'p, 's> { places.min() } + /// Whether `checkSourceFile` visits a class or interface declaration of `sym` before the file + /// of the task. It requests the base types of every one that it visits, so with one checker + /// those of `sym` are resolved by now. + pub(super) fn are_base_types_resolved_by_check(&self, sym: Sym) -> bool { + let own = self.task.file.filter(|_| self.task.checker_count == 0); + own.is_some_and(|own| { + let before = self.files().rank_of_file(own); + self.first_declaration_checked_before(sym, before).is_some() + }) + } + /// What `reportCircularBaseType` reports at the class or interface `declaration` of `sym`. fn circular_base_type( &mut self, @@ -2792,21 +2968,18 @@ impl<'p, 's> Checker<'p, 's> { file: FileId, declaration: Decl, ) -> Option { - // `GetErrorRangeForNode` - let start = declaration.name_pos_of_class_or_interface(self.hir(file))?; - let at = (file, start, self.end_of_token_at(file, start)); + let (start, end) = self.error_range_of_declaration(file, declaration)?; let ty = self.declared_type(sym); - Some(self.new_diagnostic(at, 2310, &[Arg::Type(ty)])) + let name = self.type_to_string_with_generic_arrays(ty); + Some(self.new_diagnostic((file, start, end), 2310, &[Arg::Bytes(&name)])) } /// `getReducedType`, `isErrorType`, `isValidBaseType`: `base` as a base type of the class or - /// interface whose base types are being resolved, if it is valid. `extending`: the declaration - /// with the heritage clause. `report`: called with an invalid base type, both reduced and - /// unreduced. + /// interface whose base types are being resolved, if it is valid. `report`: called with an + /// invalid base type, both reduced and unreduced. fn as_base_type( &mut self, base: TypeId, - extending: (FileId, Decl), report: impl FnOnce(&mut Self, TypeId, TypeId), ) -> Option { let unreduced = base; @@ -2823,13 +2996,7 @@ impl<'p, 's> Checker<'p, 's> { mapper, } = *self.data(part) { - let was_in_cycle = self.is_innermost_in_cycle(); self.mapped_constraint(file, node, mapper); - if !was_in_cycle && self.is_innermost_in_cycle() { - self.report_circular_mapped_key(file, node, extending); - let key = (file, node, mapper); - (self.p.circular_mapped_constraints).insert(&self.task, key, (), Stored::new()); - } } } let base = self.reduced(base); @@ -2906,9 +3073,9 @@ impl<'p, 's> Checker<'p, 's> { if hir.is_js && most > 0 { let params = self.type_params_of_symbol(base); let filled = self.fill_type_args_as(¶ms, &args, true); - return self.type_reference(base, &filled); + return self.type_reference_of_node(base, &filled); } - return self.type_reference(base, &args); + return self.type_reference_of_node(base, &args); } let sigs = self.signatures(constructor, true); let args = self.types_from_nodes(file, type_arguments); @@ -3025,7 +3192,7 @@ impl<'p, 's> Checker<'p, 's> { { self.type_of_prop(prop, MapperId::IDENTITY); } - PropSource::Mapped(..) => { + PropSource::Mapped(..) | PropSource::ReverseMapped(..) => { self.type_of_prop(prop, MapperId::IDENTITY); } _ => {} @@ -3045,10 +3212,10 @@ impl<'p, 's> Checker<'p, 's> { let member = self.type_of_literal_prop(file, p); self.resolve_spread_symbols_in(member, is_widening); } - // `getTypeOfAccessors`, where the getter comes first. `getWidenedProperty` returns at - // `prop.Flags&ast.SymbolFlagsProperty == 0`. + // `getTypeOfAccessors`, where the getter comes first. PropKind::Getter | PropKind::Setter - if !is_widening && self.member_name(file, prop.key).is_some() => + if self.member_name(file, prop.key).is_some() + && (!is_widening || self.is_accessor_widened_as_property(file, p)) => { let getter = match hir[prop.value].kind { ExprKind::Fn(setter) if prop.kind == PropKind::Setter => { @@ -3065,6 +3232,27 @@ impl<'p, 's> Checker<'p, 's> { } } + /// Whether `getWidenedProperty` passes `prop.Flags&ast.SymbolFlagsProperty == 0` for the accessor + /// `p` of an object literal. `checkObjectLiteral` puts `member` itself in `propertiesTable`, + /// which a plain member of that name shares (`PropertyExcludes`). A later member of that name + /// takes its place there. + fn is_accessor_widened_as_property(&mut self, file: FileId, p: PropId) -> bool { + if !self + .flags_of_literal_member(file, p) + .contains(SymFlags::PROPERTY) + { + return false; + } + let owner = self.bound(file).prop_owner[p.idx()]; + let owner = self.hir(file).exprs.get(owner.idx()); + let Some(ExprKind::Object(props)) = owner.map(|owner| owner.kind) else { + return false; + }; + let name = self.name_of_literal_member(file, p); + let mut later = props.iter().skip_while(|&q| q != p).skip(1); + !later.any(|q| self.name_of_literal_member(file, q) == name) + } + /// `resolve_spread_symbols` goes on with `member`, the type of a property. fn resolve_spread_symbols_in(&mut self, member: TypeId, is_widening: bool) { let flags = self.types().object_flags(member); @@ -3110,14 +3298,14 @@ impl<'p, 's> Checker<'p, 's> { match self.data(ty) { &TypeData::Anon { origin: - Origin::ObjectLiteral(file, e, is_js_literal, of_declaration, object_flags, true), + Origin::ObjectLiteral(file, e, is_js_literal, created_by, object_flags, true), mapper, } => self.intern(TypeData::Anon { origin: Origin::ObjectLiteral( file, e, is_js_literal, - of_declaration, + created_by, object_flags, false, ), @@ -3144,6 +3332,9 @@ impl<'p, 's> Checker<'p, 's> { /// `anonymous_members_in_place` says. fn origin_shape_in_the_meantime(&mut self, key: TypeId, origin: Origin) -> Shape<'s> { if self.is_late_binding(key) { + if let Origin::ClassStatic(sym) | Origin::Function(sym) = origin { + self.note_members_from_early_symbols(sym, true); + } return self.build_origin_shape( origin, MemberBinding::Early, @@ -3163,6 +3354,42 @@ impl<'p, 's> Checker<'p, 's> { Some((found.1, found.2)) } + /// `symbol.Flags&SymbolFlagsPrototype != 0`: `symbol` is the `prototype` that + /// `bindClassLikeDeclaration` puts among the exports of a class. Nothing takes its place there, + /// and the symbol of a declaration that `declareSymbolEx` refuses is in no table. + pub(super) fn is_prototype_symbol(&self, symbol: Sym) -> bool { + let files = self.files(); + files.symbol(symbol).name == known::prototype + && files.parent_of_symbol(symbol).is_some_and(|class| { + files.flags(class).contains(SymFlags::CLASS) + && files.export(class, known::prototype) == Some(files.canonical(symbol)) + }) + } + + /// `prop.Flags&SymbolFlagsPrototype != 0`. It is synthesized unless a static member declares it. + pub(super) fn is_prototype_of_class(&self, prop: &Prop) -> bool { + prop.name == known::prototype + && match prop.source { + PropSource::Type(_) => true, + PropSource::Symbol(symbol) => self.is_prototype_symbol(symbol), + _ => false, + } + } + + /// `getTypeOfPrototypeProperty` for the `prototype` of `class`: `any` for each type parameter, + /// including the outer type parameters of the class. + pub(super) fn get_type_of_prototype_property(&mut self, class: Sym) -> TypeId { + let declared = self.declared_type(class); + let count = self.type_arguments(declared).len(); + match self.data(declared) { + TypeData::Ref { target, .. } if count != 0 => self.intern_key(TypeKey::Ref { + target: *target, + args: &vec![TypeId::ANY; count], + }), + _ => declared, + } + } + /// `binding`: of the exports of a class or a function. `until`: what the result has of the /// members of a class or an enum as a value. Short of `MembersInPlace::Signatures` it is what /// a caller finds in place, and nothing is asked that `resolveAnonymousTypeMembers` has not @@ -3173,6 +3400,12 @@ impl<'p, 's> Checker<'p, 's> { binding: MemberBinding, until: MembersInPlace, ) -> Shape<'s> { + let binding = match origin { + Origin::ClassStatic(sym) | Origin::Function(sym) => { + self.binding_of_side(sym, true, binding) + } + _ => binding, + }; let early = binding == MemberBinding::Early; let is_whole = until == MembersInPlace::Signatures; let mut b = Builder::new_in(self.arena); @@ -3264,31 +3497,37 @@ impl<'p, 's> Checker<'p, 's> { } } let _ = is_abstract; + // `declareSymbolEx` adds a static property or accessor of that name to the symbol + // that `bindClassLikeDeclaration` has put in the table. What it refuses is in no + // table. + let declared_prototype = b.position(known::prototype).filter(|&i| { + matches!(b.shape.props[i].source, PropSource::Symbol(it) + if self.is_prototype_symbol(it)) + }); + match declared_prototype { + // Neither `getTypeOfPrototypeProperty` nor `getTypeOfAccessors` adds `undefined`. + Some(i) if b.shape.props[i].flags.contains(PropFlags::OPTIONAL) => { + b.shape.props[i].flags |= PropFlags::WITHOUT_OPTIONALITY; + } + Some(_) => {} + None => b.remove(known::prototype), + } let own = b.shape.props.len(); // `declare function C(): T` next to `declare class C`. b.shape.call = self.sigs_of_function_declarations(sym); - // `getTypeOfPrototypeProperty`: `any` for each type parameter, including the outer - // type parameters of the class. - // It can be assigned to (`isReadonlySymbol`). - let declared = self.declared_type(sym); - let count = self.type_arguments(declared).len(); - let instance = match self.data(declared) { - TypeData::Ref { target, .. } if count != 0 => self.intern_key(TypeKey::Ref { - target: *target, - args: &vec![TypeId::ANY; count], - }), - _ => declared, - }; - b.add(Prop { - name: known::prototype, - flags: PropFlags::empty(), - source: PropSource::Type(instance), - mapper: MapperId::IDENTITY, - }); + if declared_prototype.is_none() { + let instance = self.get_type_of_prototype_property(sym); + b.add_new(Prop { + name: known::prototype, + flags: PropFlags::empty(), + source: PropSource::Type(instance), + mapper: MapperId::IDENTITY, + }); + } let exports_from = b.shape.props.len(); self.add_namespace_exports(&mut b, sym); - // The static members, and the exports of a merged namespace. `prototype` has no - // declaration. + // The static members, and the exports of a merged namespace, but not a `prototype` + // without a declaration. contained = [0..own, exports_from..b.shape.props.len()]; ranges = self.ranges_of_declarations(sym); let at = self.anonymous_members_in_place.len(); @@ -3539,10 +3778,17 @@ impl<'p, 's> Checker<'p, 's> { /// `symbolIsValue`: a value itself, or an alias whose resolution chain reaches a value with no /// type-only step before it (`getSymbolFlagsEx`, `excludeTypeOnlyMeanings`). An alias that does /// not resolve is an error, and an error symbol has every meaning, including value. - pub(super) fn symbol_is_value(&self, sym: Sym) -> bool { - self.files() - .symbol_flags_ex(sym, true, false) - .intersects(SymFlags::VALUE) + pub(super) fn symbol_is_value(&mut self, sym: Sym) -> bool { + let excluded = ExcludedMeanings { + type_only: true, + local: false, + }; + let flags = self.get_symbol_flags_ex(sym, excluded); + // `resolveAlias` reports why it finds no target. + if flags == SymFlags::all() { + self.check_target_of_alias_symbol(sym); + } + flags.intersects(SymFlags::VALUE) } /// `PropFlags` of an export of a module, namespace or enum. Constants and enum members are read-only (`isReadonlySymbol`); the @@ -3884,19 +4130,19 @@ impl<'p, 's> Checker<'p, 's> { let has_mixins = is_mixin.contains(&true); for (at, &written) in parts.iter().enumerate() { let part = self.apparent_type(written); - // `getTypeWithThisArgument`: `this` in a member of a constituent is the whole - // intersection, unless the constituent specifies its own. In the constraint of a type - // parameter it is the type parameter (`getApparentType`). - let stands_for = if self.is_deferred(written) { - written - } else { - whole - }; // `getPropertiesOfType`, `getIndexInfosOfType`, `getSignaturesOfType`: for a union, the // members common to all its constituents. let union = self.is_union(part).then_some(part); let part = union.map_or(part, |union| self.union_as_object(union)); - let Some(members) = self.members_with_this(part, stands_for) else { + // `getTypeWithThisArgument`: `this` in a member of a constituent is the whole + // intersection, unless the constituent specifies its own, as the apparent type of a + // type variable does. + let members = if self.is_deferred(written) { + self.members_of_apparent_type(written, part) + } else { + self.members_with_this(part, whole) + }; + let Some(members) = members else { continue; }; let (call, construct) = match union { @@ -4166,11 +4412,10 @@ impl<'p, 's> Checker<'p, 's> { self.get_spread_type(left, right, false, &mut 0) } - /// `getSpreadSymbol(prop, readonly)`: the source and the mapper of the symbol it returns for - /// `prop`, a property of a type whose members have the mapper `mapper`, and the flags that - /// `type_of_prop` needs with that source. - /// Where it returns `prop` itself, the type of a declared symbol or a mapped symbol is left - /// unresolved, since it may be the one that is being resolved: + /// `getSpreadSymbol(prop, readonly)` for `prop`, a property of a type whose members have the + /// mapper `mapper`. + /// Where it returns `prop` itself, the type of a declared, a mapped or a reverse mapped symbol + /// is left unresolved, since it may be the one that is being resolved: /// `class C { x = f({ ...new C() }) }`. `get_widened_type` and `regular_type_of_object_literal` /// resolve it, where tsgo calls `getTypeOfSymbol` for every property. pub(super) fn get_spread_symbol( @@ -4178,59 +4423,56 @@ impl<'p, 's> Checker<'p, 's> { prop: &Prop, mapper: MapperId, options: SpreadSymbolOptions, - ) -> (PropSource<'s>, MapperId, PropFlags) { + ) -> Prop<'s> { let SpreadSymbolOptions { + owner, owner_is_generic, readonly, resolves, } = options; - let copy = |ty, has_value_declaration| { - let source = Self::copy_of(ty, &[prop], has_value_declaration, self.arena); - (source, MapperId::IDENTITY, PropFlags::empty()) - }; - if prop.flags.contains(PropFlags::WRITE_ONLY) { - return copy(TypeId::UNDEFINED, false); - } - let is_readonly = self.is_readonly_symbol(prop); - if !resolves - && is_readonly == readonly - && matches!(prop.source, PropSource::Symbol(_) | PropSource::Mapped(..)) - { - let composed = self.compose(prop.mapper, mapper); - // `Types::object_flags` finds the type variables of such a property in its mapper. The - // members of a type literal in a generic declaration have none. - let mapping = self.types().mapping(composed); - if !owner_is_generic || mapping.iter().any(|it| self.has_type_variables(it.1)) { - let read_with = - PropFlags::WITHOUT_OPTIONALITY | PropFlags::WIDEN | PropFlags::REGULAR; - return ( - prop.source.clone_in(self.arena), - composed, - prop.flags & read_with, - ); + let is_setonly_accessor = prop.flags.contains(PropFlags::WRITE_ONLY); + let is_same_symbol = !is_setonly_accessor && readonly == self.is_readonly_symbol(prop); + let mut flags = + prop.flags & PropFlags::OPTIONAL | self.name_flag_of_copy(owner, prop, !is_same_symbol); + flags.set(PropFlags::READONLY, readonly); + if is_same_symbol { + // A method remains a method, an accessor an accessor. + flags |= prop.flags & (PropFlags::METHOD | PropFlags::ACCESSOR); + if self.is_function_symbol_property(prop) { + flags |= PropFlags::METHOD; + } + let is_resolved_on_demand = matches!( + prop.source, + PropSource::Symbol(_) | PropSource::Mapped(..) | PropSource::ReverseMapped(..) + ); + if !resolves && is_resolved_on_demand { + let composed = self.compose(prop.mapper, mapper); + // `Types::object_flags` finds the type variables of such a property in its mapper. + // The members of a type literal in a generic declaration have none. + let mapping = self.types().mapping(composed); + if !owner_is_generic || mapping.iter().any(|it| self.has_type_variables(it.1)) { + let read_with = + PropFlags::WITHOUT_OPTIONALITY | PropFlags::WIDEN | PropFlags::REGULAR; + return Prop { + name: prop.name, + flags: flags | prop.flags & read_with, + source: prop.source.clone_in(self.arena), + mapper: composed, + }; + } } } - let ty = self.type_of_prop(prop, mapper); - copy(ty, is_readonly == readonly) - } - - /// `isReadonlySymbol` for a getter written in an object literal: it has no setter. `None`: - /// `prop` is not such a getter. - fn is_readonly_getter_of_literal(&mut self, prop: &Prop) -> Option { - let PropSource::Literal(file, p) = prop.source else { - return None; + let ty = if is_setonly_accessor { + TypeId::UNDEFINED + } else { + self.type_of_prop(prop, mapper) }; - let hir = self.hir(file); - if hir[p].kind != PropKind::Getter { - return None; + Prop { + name: prop.name, + flags, + source: Self::copy_of(ty, &[prop], is_same_symbol, self.arena), + mapper: MapperId::IDENTITY, } - let ExprKind::Fn(getter) = hir[hir[p].value].kind else { - return None; - }; - Some( - self.sibling_accessor(file, getter, FnKind::Setter) - .is_none(), - ) } /// The members of the union `ty` in the order `mapType` visits them. @@ -4248,8 +4490,7 @@ impl<'p, 's> Checker<'p, 's> { } } - /// `getSpreadType`. `readonly`: in a const context. The caller marks the properties of the - /// result. `rank`: see `Shape::spread_rank`. + /// `getSpreadType`. `readonly`: in a const context. `rank`: see `Shape::spread_rank`. pub(super) fn get_spread_type( &mut self, left: TypeId, @@ -4342,10 +4583,11 @@ impl<'p, 's> Checker<'p, 's> { let is_jsx = |c: &Self, t: TypeId| matches!(c.data(t), TypeData::Synth(shape) if shape.literal == Literalness::JsxAttributes); let (left_is_jsx, right_is_jsx) = (is_jsx(self, left), is_jsx(self, right)); // Properties declared in the literal itself remain marked as such - // (`shouldCheckAsExcessProperty`): on the left in the accumulated spread result, on the - // right in a run of properties between spreads. + // (`shouldCheckAsExcessProperty`): on the left in the accumulated spread result, or in the + // run that follows a generic spread (`lastLeft`), on the right in a run of properties + // between spreads. let left_is_so_far = left_is_jsx - || matches!(self.data(left), TypeData::Synth(shape) if shape.literal == Literalness::WithSpread); + || matches!(self.data(left), TypeData::Synth(shape) if matches!(shape.literal, Literalness::WithSpread | Literalness::Written)); let right_is_written = right_is_jsx || matches!(self.data(right), TypeData::Synth(shape) if shape.literal == Literalness::Written); // `getSpreadSymbol` returns the same symbol, so the synthesized JSX children property keeps @@ -4373,36 +4615,21 @@ impl<'p, 's> Checker<'p, 's> { { continue; } - if left_is_so_far && is_written(prop) { - b.add(prop.clone_in(self.arena)); - continue; - } // `getSpreadSymbol`: a write-only property reads as `undefined`. It is recreated, and so // is a property that is readonly where the result is not, or the reverse. let anew = prop.flags.contains(PropFlags::WRITE_ONLY) || prop.flags.contains(PropFlags::READONLY) != readonly; - // A property that is not recreated is the same symbol: a method remains a method. - let kept = if anew { - PropFlags::OPTIONAL - } else { - PropFlags::OPTIONAL | PropFlags::METHOD - }; - let mut flags = prop.flags & kept | self.name_flag_of_copy(left, prop, anew); - if !anew && self.is_function_symbol_property(prop) { - flags |= PropFlags::METHOD; + if left_is_so_far && !anew && is_written(prop) { + b.add(prop.clone_in(self.arena)); + continue; } let options = SpreadSymbolOptions { + owner: left, owner_is_generic: left_is_generic, readonly, resolves: false, }; - let (source, mapper, read_with) = self.get_spread_symbol(prop, l.mapper, options); - b.add(Prop { - name: prop.name, - flags: flags | read_with, - source, - mapper, - }); + b.add(self.get_spread_symbol(prop, l.mapper, options)); } for prop in &r.shape().props { // `skippedPrivateMembers`: it hides the existing property of that name, and is not @@ -4418,22 +4645,14 @@ impl<'p, 's> Checker<'p, 's> { continue; } let is_write_only = prop.flags.contains(PropFlags::WRITE_ONLY); - if right_is_written && !is_write_only && is_written(prop) { - // `getSpreadSymbol`: `links.resolvedType = c.getTypeOfSymbol(prop)`. Of the members - // written in a literal only an accessor can differ from `readonly`. - if self - .is_readonly_getter_of_literal(prop) - .is_some_and(|is_readonly| is_readonly != readonly) - { - self.type_of_prop(prop, r.mapper); - } + let anew = is_write_only || prop.flags.contains(PropFlags::READONLY) != readonly; + let is_merged = prop.flags.contains(PropFlags::OPTIONAL) && b.has(prop.name); + if right_is_written && !anew && !is_merged && is_written(prop) { b.remove(prop.name); b.add_new(prop.clone_in(self.arena)); continue; } - let (flags, source); - let mut mapper = MapperId::IDENTITY; - if prop.flags.contains(PropFlags::OPTIONAL) + let copy = if prop.flags.contains(PropFlags::OPTIONAL) && let Some(i) = b.position(prop.name) { let mut ty = if is_write_only { @@ -4448,7 +4667,7 @@ impl<'p, 's> Checker<'p, 's> { Some(original) => self.name_flag_of_copy(left, original, true), None => existing.flags & PropFlags::STRING_NAME, }; - flags = existing.flags & PropFlags::OPTIONAL | named; + let flags = existing.flags & PropFlags::OPTIONAL | named; // `getSpreadType`: the type on the left, or the type on the right when that // property is present. let left_present = self.remove_missing_or_undefined_type(left_ty); @@ -4458,39 +4677,23 @@ impl<'p, 's> Checker<'p, 's> { } else { self.union_reduced(&[left_ty, present]) }; - source = Self::copy_of(ty, &[&b.shape.props[i], prop], false, self.arena); + Prop { + name: prop.name, + flags, + source: Self::copy_of(ty, &[&b.shape.props[i], prop], false, self.arena), + mapper: MapperId::IDENTITY, + } } else { - let anew = is_write_only || prop.flags.contains(PropFlags::READONLY) != readonly; - let kept = if anew { - PropFlags::OPTIONAL - } else { - PropFlags::OPTIONAL | PropFlags::METHOD - }; - let function_flag = if !anew && self.is_function_symbol_property(prop) { - PropFlags::METHOD - } else { - PropFlags::empty() - }; // `rightType := c.getTypeOfSymbol(rightProp)`, for a property that the left has too. let replaces = (l.resolved.prop(prop.name)) .is_some_and(|earlier| self.is_spreadable_property(earlier)); let options = SpreadSymbolOptions { + owner: right, owner_is_generic: right_is_generic, readonly, resolves: replaces, }; - let read_with; - (source, mapper, read_with) = self.get_spread_symbol(prop, r.mapper, options); - flags = prop.flags & kept - | self.name_flag_of_copy(right, prop, anew) - | function_flag - | read_with; - } - let copy = Prop { - name: prop.name, - flags, - source, - mapper, + self.get_spread_symbol(prop, r.mapper, options) }; match b.position(prop.name) { Some(i) if prop.flags.contains(PropFlags::OPTIONAL) => b.shape.props[i] = copy, @@ -4502,22 +4705,19 @@ impl<'p, 's> Checker<'p, 's> { } } self.get_named_members(&mut b.shape.props, |_| true, &[]); - // `getIndexInfoWithReadonly`: a copy is writable, whatever it is a copy of. + // `getIndexInfoWithReadonly` if left == TypeId::EMPTY_OBJECT { for info in &r.shape().index { let value = self.instantiate(info.value, r.mapper); b.shape.index.push(IndexInfo { value, - readonly: false, + readonly, ..*info }); } } else if !l.shape().index.is_empty() { for info in self.union_index_infos(&[left, right]) { - b.shape.index.push(IndexInfo { - readonly: false, - ..info - }); + b.shape.index.push(IndexInfo { readonly, ..info }); } } b.shape.literal = if left_is_jsx || right_is_jsx { @@ -4580,7 +4780,9 @@ impl<'p, 's> Checker<'p, 's> { } } }; - let is_instantiated = self.has_type_variables(base) + let is_changed = + ObjectFlags::COULD_CONTAIN_TYPE_VARIABLES | ObjectFlags::HAS_OTHER_INSTANTIATION; + let is_instantiated = self.types().object_flags(base).intersects(is_changed) && match prop.source { PropSource::Symbol(sym) => !self.is_thisless_for_this_mapper(sym), _ => true, @@ -4610,8 +4812,8 @@ impl<'p, 's> Checker<'p, 's> { /// `m.MapsThisOnly() && isThisless(symbol)`: whether `instantiateSymbol` returns the member /// `sym` of a class or an interface itself. `m` is the mapper of `resolveObjectTypeMembers`, /// whose sources are the type parameters of the class or interface, the outer ones too, and - /// its `this` type. - fn is_thisless_for_this_mapper(&mut self, sym: Sym) -> bool { + /// its `this` type. Without a `this` type there is no mapper (`resolveClassOrInterfaceMembers`). + pub(super) fn is_thisless_for_this_mapper(&mut self, sym: Sym) -> bool { let Some((file, Decl::Member(m))) = self.files().value_declaration(sym) else { return false; }; @@ -4621,12 +4823,12 @@ impl<'p, 's> Checker<'p, 's> { MemberOwner::Interface(i) => (hir[i].type_params, bound.interface_symbol[i.idx()]), _ => return false, }; - type_params.is_empty() - && owner.is_some() - && self.is_thisless(sym) - && self - .outer_type_params_of_symbol(self.files().sym(file, owner)) - .is_empty() + if !type_params.is_empty() || owner.is_none() { + return false; + } + let owner = self.files().sym(file, owner); + (self.is_thisless(sym) || !self.has_this_type(owner)) + && self.outer_type_params_of_symbol(owner).is_empty() } /// `isThisless`, for a member of a class or an interface. @@ -4681,11 +4883,11 @@ impl<'p, 's> Checker<'p, 's> { declaration: UntypedProperty, ) -> (FileId, u32, u32) { match declaration { - UntypedProperty::Member(member) => ( - file, - self.hir(file)[member].name_pos, - self.end_of_member_name(file, member), - ), + UntypedProperty::Member(member) => { + let (hir, end) = (self.hir(file), self.end_of_member_name(file, member)); + let start = super::spans::start_of_error_range(hir, hir[member].name_pos, end); + (file, start, end) + } UntypedProperty::Assignment(e) => ( file, self.start_inside_parentheses(file, e), @@ -4714,11 +4916,11 @@ impl<'p, 's> Checker<'p, 's> { let at = self.place_of_untyped_property(file, declaration); // `DeclarationNameToString(GetNameOfDeclaration(declaration))` let name = match declaration { - UntypedProperty::Member(_) => self.source_text(file, at.1, at.2), - UntypedProperty::Assignment(e) => self - .name_of_assignment_declaration(file, e) - .unwrap_or_else(|| b"(Missing)".to_vec()), + UntypedProperty::Member(_) if at.1 != at.2 => Some(self.source_text(file, at.1, at.2)), + UntypedProperty::Member(_) => None, + UntypedProperty::Assignment(e) => self.name_of_assignment_declaration(file, e), }; + let name = name.unwrap_or_else(|| b"(Missing)".to_vec()); let diagnostic = self.new_diagnostic(at, code, &[Arg::Bytes(&name), Arg::Type(ty)]); self.add_error_or_suggestion(no_implicit_any, diagnostic); } @@ -4763,22 +4965,15 @@ impl<'p, 's> Checker<'p, 's> { if type_annotation.is_some() { return ThisAssignmentDeclaration::Typed(type_annotation); } - // `getDeclaringConstructor` - let constructor = declarations.iter().find_map(|&declaration| { - let e = assignment_declaration_in(file, declaration)?; - match self.this_container(file, e) { - Some(Ok(func)) if hir[func].kind == FnKind::Constructor => Some(func), - _ => None, - } - }); + let constructor = self.get_declaring_constructor(file, declarations); constructor.map_or( ThisAssignmentDeclaration::Method, ThisAssignmentDeclaration::Constructor, ) } - /// `getWidenedTypeForAssignmentDeclaration` for the symbol `name` of `file` whose - /// `Declarations` are `declarations`. + /// `getWidenedTypeForAssignmentDeclaration` for the symbol `name` whose `Declarations` are + /// `declarations` and whose `ValueDeclaration` is `value_declaration`, in `file`. pub(super) fn get_widened_type_for_assignment_declaration( &mut self, file: FileId, @@ -4787,7 +4982,6 @@ impl<'p, 's> Checker<'p, 's> { value_declaration: ExprId, ) -> TypeId { use crate::bind::{JsDeclarationKind, assignment_declaration_kind}; - let hir = self.hir(file); let kind = self.is_constructor_declared_this_property(file, declarations); let inherited = |c: &mut Self| { let class = c.class_of_this_property(file, value_declaration)?; @@ -4813,13 +5007,14 @@ impl<'p, 's> Checker<'p, 's> { let mut types = Vec::with_capacity(declarations.len()); let mut declared = None; for (i, &declaration) in declarations.iter().enumerate() { - let Some(e) = assignment_declaration_in(file, declaration) else { + let Some((of, e)) = assignment_declaration(declaration) else { continue; }; + let hir = self.hir(of); // `declaration.Type()`: the first annotated declaration decides. let annotation = hir.jsdoc_type(JsDocTypeOwner::Assign(e)); if annotation.is_some() { - declared = Some(self.type_from_node(file, annotation)); + declared = Some(self.type_from_node(of, annotation)); break; } // `getAssignmentDeclarationInitializerType` @@ -4827,16 +5022,14 @@ impl<'p, 's> Checker<'p, 's> { ExprKind::Assign { target, value, .. } => { if assignment_declaration_kind(hir, e) == JsDeclarationKind::ThisProperty - && self.contains_same_named_this_property(file, target, value) + && self.contains_same_named_this_property(of, target, value) { continue; } - self.type_of_assignment_declaration(file, e, target, value) + self.type_of_assignment_declaration(of, e, value) } ExprKind::Call(call) => match hir.ids(hir[call].args).nth(2) { - Some(descriptor) => { - self.type_from_property_descriptor(file, descriptor) - } + Some(descriptor) => self.type_from_property_descriptor(of, descriptor), None => continue, }, _ => continue, @@ -4870,7 +5063,23 @@ impl<'p, 's> Checker<'p, 's> { }; let ty = self.widened(ty); // "report an all-nullable or empty union as an implicit any in JS files" - if hir.is_js && self.is_all_null_or_undefined(ty) { + if self.hir(file).is_js && self.is_all_null_or_undefined(ty) { + // `checkBinaryExpression` asks for the type of the symbol that an assignment declares, + // `checkCallExpression` does not ask for that of `Object.defineProperty(f, "name", d)`. + let is_asked_by_check = declarations.iter().any(|&declaration| { + assignment_declaration(declaration) + .is_none_or(|(of, e)| !matches!(self.hir(of)[e].kind, ExprKind::Call(_))) + }); + if !is_asked_by_check + && self.task.checker_count == 0 + && !self.is_emitting + && !self.is_reported_in_time_on_request(file) + { + // One checker has collected the diagnostics of `file` by now. Nothing is stored, so + // the task of a file that asks in time evaluates this, and reports. + self.mark_tainted_from(self.frames.len().saturating_sub(1)); + return TypeId::ANY; + } let value_declaration = UntypedProperty::Assignment(value_declaration); self.report_implicit_any(file, value_declaration, TypeId::ANY); return TypeId::ANY; @@ -5023,7 +5232,7 @@ impl<'p, 's> Checker<'p, 's> { let flags = self.files().flags(sym); if flags.contains(SymFlags::ASSIGNMENT) { return (self.assignments_of_symbol(sym).iter()) - .any(|&e| self.is_readonly_assignment_declaration(sym.file, e)); + .any(|&(file, e)| self.is_readonly_assignment_declaration(file, e)); } // `Object.defineProperty(exports, "name", descriptor)` return flags.contains(SymFlags::FUNCTION_SCOPED_VARIABLE) @@ -5040,13 +5249,11 @@ impl<'p, 's> Checker<'p, 's> { (declared.iter()).any(|declared| self.has_readonly_assignment_declaration(declared)) } - /// `getAssignmentDeclarationInitializerType` for `declaration`, the assignment `target = value`, which declares the property - /// `target`. + /// `getAssignmentDeclarationInitializerType` for `declaration`, an assignment of `value` that declares a property. fn type_of_assignment_declaration( &mut self, file: FileId, declaration: ExprId, - target: ExprId, value: ExprId, ) -> TypeId { use crate::bind::{JsDeclarationKind, assignment_declaration_kind}; @@ -5067,14 +5274,21 @@ impl<'p, 's> Checker<'p, 's> { // object literal gets a separate type. TypeData::Anon { origin: - Origin::ObjectLiteral(of, literal, is_js_literal, false, object_flags, is_fresh), + Origin::ObjectLiteral( + of, + literal, + is_js_literal, + ObjectLiteralCheck::ForParent, + object_flags, + is_fresh, + ), mapper, } if (of, literal) == (file, value) => self.intern(TypeData::Anon { origin: Origin::ObjectLiteral( of, literal, is_js_literal, - true, + ObjectLiteralCheck::ForAssignmentDeclaration, object_flags, is_fresh, ), @@ -5082,9 +5296,8 @@ impl<'p, 's> Checker<'p, 's> { }), _ => ty, }; - // The property is `any[]`, unless its owner initializes a variable that has a type annotation. if self.is_empty_array_literal_type(ty) - && !self.is_property_of_annotated_variable(file, target) + && !self.has_parent_with_type_annotation(file, declaration) { let any_array = self.array_of(TypeId::ANY); self.report_implicit_any(file, UntypedProperty::Assignment(declaration), any_array); @@ -5099,20 +5312,71 @@ impl<'p, 's> Checker<'p, 's> { self.widen_literal_for_context(ty, expected) } - /// `hasParentWithTypeAnnotation`: whether `target` is `f.name` or `f[key]` of a variable `f` - /// that has a type annotation. - pub(super) fn is_property_of_annotated_variable(&self, file: FileId, target: ExprId) -> bool { - let (hir, bound) = (self.hir(file), self.bound(file)); - let (ExprKind::Dot { obj, .. } | ExprKind::Index { obj, .. }) = hir[target].kind else { + /// `hasParentWithTypeAnnotation(node.Symbol())` for the assignment `node`. + fn has_parent_with_type_annotation(&mut self, file: FileId, node: ExprId) -> bool { + use crate::bind::{JsDeclarationKind, assignment_declaration_kind}; + let (hir, bound, files) = (self.hir(file), self.bound(file), self.files()); + // The parent of an export is the file. + let Some(symbol) = bound.symbols.get(bound.expr_symbol[node.idx()].idx()) else { return false; }; - let symbol = bound.expr_symbol[obj.idx()]; - matches!(hir[obj].kind, ExprKind::Ident(_)) - && symbol.is_some() - && bound.symbols[symbol.idx()].decls.iter().any(|&d| match d { - Decl::Var(pat) => matches!(bound.pat_parent[pat.idx()], crate::bind::PatParent::Var(v) if hir[v].ty.is_some()), - _ => false, - }) + // `symbol.Parent.ValueDeclaration` + let function = if symbol.name == known::computed && bound.is_expando_declaration(node) { + // `bindAnonymousDeclaration`: `symbol.Parent = b.container.Symbol()`. `Symbol::parent` + // is that of the late bound symbol. + hir.find_ancestor(hir.parent(hir.node(node)), |it| is_container(hir.kind(it))) + } else { + let parent = bound.symbols.get(symbol.parent.idx()); + parent + .and_then(|parent| parent.decls.get(parent.value_declaration as usize)) + .map_or(Node::NONE, |&declaration| hir.node(declaration)) + }; + if function.is_none() + || !matches!( + hir.kind(function), + Kind::FunctionExpression | Kind::ArrowFunction + ) + { + return false; + } + // `getSymbolOfNode(function.Parent)` + let declaration = match hir.data(hir.parent(function)) { + NodeData::VarDecl(d) => Decl::Var(hir[d].pat), + NodeData::Param(p) => Decl::Param(hir[p].pat), + NodeData::Member(m) => Decl::Member(m), + NodeData::Prop(p) => Decl::Property(p), + NodeData::Stmt(s) => Decl::ExportExpr(s), + NodeData::Expr(e) => match (hir[e].kind, assignment_declaration_kind(hir, e)) { + (ExprKind::Fn(outer), _) => Decl::Fn(outer), + (_, JsDeclarationKind::ModuleExports) => Decl::ModuleExports(e), + (_, JsDeclarationKind::ExportsProperty(_)) => Decl::ExportsProperty(e), + _ => Decl::Expando(e), + }, + _ => return false, + }; + let possibly_annotated = bound.symbol_of_declaration(declaration); + let value_declaration = match bound.symbols.get(possibly_annotated.idx()) { + // `getLateBoundSymbol` + Some(symbol) if symbol.name == known::computed => { + self.value_declaration_of_property(files.sym(file, possibly_annotated)) + } + Some(_) => files.value_declaration(files.sym(file, possibly_annotated)), + // `Bound` does not have the symbol of an export, nor that of a member of an object + // literal that is its only declaration. + None => match declaration { + Decl::Property(_) => Some((file, declaration)), + Decl::ModuleExports(_) | Decl::ExportsProperty(_) => { + (bound.commonjs_indicator.is_some()).then_some((file, declaration)) + } + Decl::ExportExpr(s) => matches!( + hir[s].kind, + StmtKind::ExportDefault(_) | StmtKind::ExportAssign(_) + ) + .then_some((file, declaration)), + _ => None, + }, + }; + value_declaration.is_some_and(|(of, it)| self.type_node_of_declaration(of, it).is_some()) } /// `getWriteTypeOfSymbol`: the type that may be assigned to `prop`, which was found in a type @@ -5143,7 +5407,24 @@ impl<'p, 's> Checker<'p, 's> { let mapper = self.compose(prop.mapper, outer); return self.instantiate(all, mapper); } - if !prop.flags.contains(PropFlags::ACCESSOR) { + // The symbol itself, where `getSpreadSymbol` returns it. + let source = match &prop.source { + PropSource::Copy(_, declared, true) => match &declared[..] { + [only] => &only.source, + _ => &prop.source, + }, + source => source, + }; + // `SymbolFlagsProperty` is tested before `SymbolFlagsAccessor`, and a property shares one + // symbol with the accessors of its name. + let is_property = !prop.flags.contains(PropFlags::ACCESSOR) + || match *source { + PropSource::Symbol(sym) => self.flags_of_property(sym), + PropSource::Literal(file, p) => self.flags_of_literal_member(file, p), + _ => SymFlags::empty(), + } + .contains(SymFlags::PROPERTY); + if is_property { // `removeMissingType`: the missing type of an optional property cannot be assigned to // it. let ty = self.type_of_prop(prop, outer); @@ -5151,7 +5432,7 @@ impl<'p, 's> Checker<'p, 's> { } // `getAnnotatedAccessorTypeNode(setter)` of `getWriteTypeOfAccessors`, and the start of the // name of `setter`. - let annotation: Option<(FileId, TypeNodeId, u32)> = match &prop.source { + let annotation: Option<(FileId, TypeNodeId, u32)> = match source { PropSource::Symbol(sym) => { let members = self.members_of_symbol(*sym); let first_of = |kind: MemberKind| { @@ -5846,6 +6127,16 @@ impl<'p, 's> Checker<'p, 's> { .iter() .position(|&t| t == ty); if self.left_a_cycle || marked.is_some() { + if matches!(self.data(ty), TypeData::TypeParam(..)) + && !(self.circular_constraint_origins.iter()).any(|it| it.0 == ty) + { + let current = if self.eager.is_empty() { + self.current_node().or(self.current_source_element) + } else { + None + }; + self.circular_constraint_origins.push((ty, current)); + } // Another frame of `ty` can be in progress below a `resolution_start` barrier. Its // first read was a miss, so it learns of the cycle at its own `leave`: the mark is for // that frame too. @@ -6052,10 +6343,10 @@ impl<'p, 's> Checker<'p, 's> { ) } - /// Those of them that are assignments, in the file of the symbol. - pub(super) fn assignments_of_symbol(&mut self, sym: Sym) -> SmallVec<[ExprId; 2]> { + /// Those of them that are assignments. + pub(super) fn assignments_of_symbol(&mut self, sym: Sym) -> SmallVec<[(FileId, ExprId); 2]> { let assignment = |&(file, decl): &(FileId, Decl)| match decl { - Decl::Expando(e) | Decl::ThisProperty(e) if file == sym.file => Some(e), + Decl::Expando(e) | Decl::ThisProperty(e) => Some((file, e)), _ => None, }; (self.declarations_of_property(sym).iter()) @@ -6370,7 +6661,7 @@ impl<'p, 's> Checker<'p, 's> { part }; let members = if self.is_deferred(written) { - self.members_with_this(part, written) + self.members_of_apparent_type(written, part) } else if is_apparent { let this_argument = ty; self.members_with_this(part, this_argument) @@ -6584,14 +6875,7 @@ impl<'p, 's> Checker<'p, 's> { return (!prop.flags.contains(PropFlags::READ_PARTIAL)) .then_some((prop, MapperId::IDENTITY)); } - // `getApparentType`: in a member found through the constraint of a type parameter, `this` - // is the type parameter. - let members = if apparent != ty && self.is_deferred(ty) { - let this_argument = ty; - self.members_with_this(apparent, this_argument)? - } else { - self.members(apparent)? - }; + let members = self.members_of_apparent_type(ty, apparent)?; if self.is_type_only_member(apparent, name) { return None; } @@ -7071,15 +7355,12 @@ impl<'p, 's> Checker<'p, 's> { let FnOwner::Member(member) = bound.fns[func.idx()].owner else { return Vec::new(); }; - let MemberOwner::Interface(i) = bound.member_owner[member.idx()] else { + // `isArrayOrTupleSymbol(t.symbol.Parent)`, `isReadonlyArraySymbol(t.symbol.Parent)` + let Some(owner) = self.symbol_of_member_owner(file, member) else { return Vec::new(); }; - if bound.interface_symbol[i.idx()].is_none() || hir[i].type_params.len() != 1 { - return Vec::new(); - } - let owner = Some(self.files().sym(file, bound.interface_symbol[i.idx()])); - let is_readonly = owner == self.global_type_symbol(known::ReadonlyArray); - if !is_readonly && owner != self.global_type_symbol(known::Array) { + let is_readonly = Some(owner) == self.global_type_of_arity(known::ReadonlyArray, 1); + if !is_readonly && Some(owner) != self.global_type_of_arity(known::Array, 1) { return Vec::new(); } let name = self.declared_member_name(file, hir[member].key); @@ -7087,7 +7368,9 @@ impl<'p, 's> Checker<'p, 's> { return Vec::new(); } // The type argument for the type parameter of the array in that member. - let param = self.type_param(file, hir[i].type_params.at(0)); + let [param] = self.local_type_params_of_symbol(owner)[..] else { + return Vec::new(); + }; match self.types().map(*mapper, param) { Some(element) if element != param => elements.push(element), _ => return Vec::new(), @@ -7648,18 +7931,43 @@ impl<'p, 's> Checker<'p, 's> { } } -/// The assignment or the `Object.defineProperty` call that `declaration` is, if it is one in -/// `file`. -fn assignment_declaration_in(file: FileId, declaration: (FileId, Decl)) -> Option { - match declaration.1 { +/// `GetContainerFlags(node)&ContainerFlagsIsContainer != 0` for a node of that kind. +fn is_container(kind: Kind) -> bool { + kind.is_function_like() + || kind.is_class_like() + || matches!( + kind, + Kind::EnumDeclaration + | Kind::ObjectLiteralExpression + | Kind::TypeLiteral + | Kind::JsxAttributes + | Kind::InterfaceDeclaration + | Kind::ModuleDeclaration + | Kind::TypeAliasDeclaration + | Kind::JSTypeAliasDeclaration + | Kind::MappedType + | Kind::SourceFile + | Kind::ClassStaticBlockDeclaration + ) +} + +/// The assignment or the `Object.defineProperty` call that `declaration` is, with its file. +pub(super) fn assignment_declaration( + (file, declaration): (FileId, Decl), +) -> Option<(FileId, ExprId)> { + match declaration { Decl::Expando(e) | Decl::ThisProperty(e) | Decl::ModuleExports(e) - | Decl::ExportsProperty(e) - if declaration.0 == file => - { - Some(e) - } + | Decl::ExportsProperty(e) => Some((file, e)), + _ => None, + } +} + +/// `assignment_declaration`, if it is in `file`. +fn assignment_declaration_in(file: FileId, declaration: (FileId, Decl)) -> Option { + match assignment_declaration(declaration)? { + (of, e) if of == file => Some(e), _ => None, } } diff --git a/src/sema/check/sink.rs b/src/sema/check/sink.rs index 2c0712175118..5331ecefbde2 100644 --- a/src/sema/check/sink.rs +++ b/src/sema/check/sink.rs @@ -99,6 +99,10 @@ pub(super) struct Reported { /// `Emit` reported it, before the check (`Options::emits_first`). It stays where /// `checkSourceFile` never comes. pub(super) by_emit: bool, + /// The check of another node than the one it points at reported it: `checkUnusedIdentifiers` + /// for the container of a declaration, `resolveAlias` for a reference. It stays where + /// `checkSourceFile` never comes. + pub(super) by_another_node: bool, /// It is a callback of `addDeferredDiagnostic` that has not been called: `args` is empty. pub(super) deferred: Option, } @@ -136,6 +140,7 @@ impl Reported { directive: NO_DIRECTIVE, was_bare: false, by_emit: false, + by_another_node: false, deferred: None, } } @@ -456,29 +461,123 @@ impl Checker<'_, '_> { } return self.discarded.insert(diagnostic); } + if self.is_reported_too_late(None, diagnostic.file) { + self.mark_tainted_from(0); + return self.discarded.insert(diagnostic); + } self.reported.push(diagnostic); self.reported.last_mut().unwrap() } - /// `getReturnTypeFromBody` checks the expression of a `return` statement with - /// `checkExpressionCached`, and so does `checkReturnStatement`. An expression body and the - /// operand of a `yield` are checked again with `checkExpression`, which stores no result and - /// creates a discarded diagnostic again. The index in `stack` of such an expression, if the - /// queries from there up are expressions that check one another. + /// `checkExpression` stores no result, and creates a discarded diagnostic again. The index in + /// `stack` of the outermost of the expressions that check one another, up to the innermost + /// query, if `checkSourceFile` checks it again. + /// - `getReturnTypeFromBody` checks the expression of a `return` statement, without its + /// parentheses, with `checkExpressionCached`, and `checkReturnStatement` with them. An + /// expression body and the operand of a `yield` are checked again with `checkExpression`. + /// - `getTypeOfExpression`, for the assigned type of a reference, stores nothing that + /// `checkExpression` reads. + /// - `checkObjectLiteral` checks every member. Here whoever reads a member first checks it. fn expressions_checked_again(&self) -> Option { + use crate::bind::Parent; + let floor = self.printing_floors.last().copied().unwrap_or(0); let is_check = |q: &&Query| matches!(q, Query::Expr(..) | Query::LiteralProp(..)); - let from = self.stack.len() - self.stack.iter().rev().take_while(is_check).count(); - if from <= self.printing_floors.last().copied().unwrap_or(0) { - return None; - } - let (Query::Return(..) | Query::ReturnAtFirstLook(..), &Query::Expr(file, outermost)) = - (self.stack[from - 1], self.stack.get(from)?) - else { - return None; + let checks = self.stack.get(floor..)?.iter().rev().take_while(is_check); + let lowest = self.stack.len() - checks.count(); + let from = (lowest + 1..self.stack.len()) + .rev() + .find(|&i| !self.is_part_of(self.stack[i], self.stack[i - 1])) + .unwrap_or(lowest); + let asked_by = (from > floor).then(|| self.stack[from - 1]); + let is_checked_again = match (*self.stack.get(from)?, asked_by) { + (Query::Expr(file, e), Some(Query::Return(..) | Query::ReturnAtFirstLook(..))) => { + let hir = self.hir(file); + is_parenthesized(hir, e) + || !matches!(self.bound(file).expr_parent[e.idx()], + Parent::Stmt(s) if matches!(hir[s].kind, StmtKind::Return(_))) + } + (Query::Expr(file, e), Some(Query::Expr(..) | Query::LiteralProp(..))) => { + let hir = self.hir(file); + match self.bound(file).expr_parent[e.idx()] { + Parent::Expr(parent) if parent.is_some() => { + matches!(hir[parent].kind, ExprKind::Assign { value, .. } if value == e) + } + Parent::Stmt(s) => { + matches!(hir[s].kind, StmtKind::ForOf { expr, .. } if expr == e) + } + _ => false, + } + } + (Query::LiteralProp(file, p), _) => self.is_member_checked_again(file, p), + _ => false, + }; + is_checked_again.then_some(from) + } + + /// Whether the check of `whole` checks `part`, through expressions and members of object + /// literals alone. + fn is_part_of(&self, part: Query, whole: Query) -> bool { + use crate::bind::Parent; + let (file, mut parent) = match part { + Query::Expr(file, e) => (file, self.bound(file).expr_parent[e.idx()]), + Query::LiteralProp(file, p) => { + (file, Parent::Expr(self.bound(file).prop_owner[p.idx()])) + } + _ => return false, }; - let is_cached = matches!(self.bound(file).expr_parent[outermost.idx()], - crate::bind::Parent::Stmt(s) if matches!(self.hir(file)[s].kind, StmtKind::Return(_))); - (!is_cached).then_some(from) + let bound = self.bound(file); + loop { + parent = match parent { + Parent::Expr(e) if e.is_some() => { + if whole == Query::Expr(file, e) { + return true; + } + bound.expr_parent[e.idx()] + } + Parent::Prop(p) => { + if whole == Query::LiteralProp(file, p) { + return true; + } + Parent::Expr(bound.prop_owner[p.idx()]) + } + _ => return false, + }; + } + } + + /// Whether `checkSourceFile` checks the member `p` of an object literal again, whatever has + /// checked the literal: no expression around it has a stored type or a resolved signature. + fn is_member_checked_again(&self, file: FileId, p: PropId) -> bool { + use crate::bind::Parent; + let (hir, bound) = (self.hir(file), self.bound(file)); + let mut e = bound.prop_owner[p.idx()]; + loop { + // The attributes of a JSX element are checked with its signature. + if e.is_none() || matches!(hir[e].kind, ExprKind::Jsx(_)) { + return false; + } + e = match bound.expr_parent[e.idx()] { + Parent::FnBody(_) => return true, + Parent::Stmt(s) => { + return match hir[s].kind { + StmtKind::Return(_) => { + is_parenthesized(hir, e) || matches!(hir[e].kind, ExprKind::Await(_)) + } + StmtKind::ExportDefault(_) | StmtKind::ExportAssign(_) => false, + _ => true, + }; + } + Parent::Prop(member) => bound.prop_owner[member.idx()], + Parent::Expr(parent) if parent.is_some() => match hir[parent].kind { + ExprKind::Yield { .. } => return true, + ExprKind::Call(_) | ExprKind::New(_) | ExprKind::TaggedTemplate(_) => { + return false; + } + _ => parent, + }, + _ => return false, + }; + } } /// `c.addDeferredDiagnostic`. `callback`: see `Reported::deferred`. @@ -507,7 +606,12 @@ impl Checker<'_, '_> { for diagnostic in self.reported.split_off(from) { self.log_diagnostic(Some(q), diagnostic); } + } else { + return; } + let requests = &self.reported_iteration_requests; + let since_entered = requests.partition_point(|request| request.0 < frame.serial); + self.settle_iteration_requests(since_entered, frame.drops_reported); } /// `settle_reported` for the innermost frame if it stores nothing under its query, before @@ -535,6 +639,13 @@ impl Checker<'_, '_> { /// - `None`: it belongs to the task. A limit, after which no query in progress is cacheable. A /// cycle that has no query. pub(super) fn add_diagnostic_of(&mut self, owner: Option, diagnostic: Reported) { + // As in `add_diagnostic`. In another file tsgo's result depends on file order, and the + // entry is stored already: the diagnostic stays with it. + if self.serialization_level >= MAX_SERIALIZATION_LEVEL + && self.task.file == Some(diagnostic.file) + { + return; + } self.log_diagnostic(owner, diagnostic); } @@ -552,9 +663,11 @@ impl Checker<'_, '_> { if self.is_type_checked && self.task.file == Some(diagnostic.file) { return; } - // `GetGlobalDiagnostics` comes after the last `checkSourceFile` and before a baseline writer. What the writer is the - // first to evaluate is not stored then, so the check of a later file that asks for it reports. - if self.is_type_checked && diagnostic.file == NOWHERE.0 { + // `GetGlobalDiagnostics` comes after the last `checkSourceFile` and before `Emit` or a baseline writer. What those are + // the first to evaluate is not stored then, so the check of a later file that asks for it reports. + if self.is_type_checked && diagnostic.file == NOWHERE.0 + || self.is_reported_too_late(owner, diagnostic.file) + { return self.mark_tainted_from(0); } diagnostic.by_emit |= self.is_emitting; @@ -603,20 +716,84 @@ impl Checker<'_, '_> { /// reported no later than the first of these files is checked: that of the task, and those /// whose syntax `owner` and the queries in progress are about. Any file can be the first to ask /// for a query about a type. No check asks for the type of a symbol that - /// `is_resolved_on_request`. + /// `is_resolved_on_request`, nor for what its pattern implies but for a name in it, and the + /// check of a declaration asks for its inferred return type only if + /// `is_inferred_return_type_requested`. pub(super) fn is_reported_in_time(&self, owner: Option, file: FileId) -> bool { + self.is_reported_in_time_under(owner, &self.stack, file) + } + + /// `is_reported_in_time` for what the innermost query reports, if no check asks for that query. + pub(super) fn is_reported_in_time_on_request(&self, file: FileId) -> bool { + let below = self.stack.len().saturating_sub(1); + self.is_reported_in_time_under(None, &self.stack[..below], file) + } + + /// `is_reported_in_time` for what follows from the state of `stack[height]`, a resolution in + /// progress: a check that begins at a query above it does not find that state. + pub(super) fn is_reported_in_time_under_resolution(&self, height: usize, file: FileId) -> bool { + self.is_reported_in_time_under(None, &self.stack[..height], file) + } + + /// `in_progress`: the queries in progress that count. + fn is_reported_in_time_under( + &self, + owner: Option, + in_progress: &[Query], + file: FileId, + ) -> bool { + (self.task.file).is_none_or(|current| self.is_checked_no_later_than(current, file)) + || self.is_asked_by_check_in_time(owner, in_progress, file) + } + + /// `is_reported_in_time_under` without the file of the task. + fn is_asked_by_check_in_time( + &self, + owner: Option, + in_progress: &[Query], + file: FileId, + ) -> bool { let is_in_time = |visited: FileId| self.is_checked_no_later_than(visited, file); let is_asked_by_check = |q: Query| match q { Query::ParameterSymbol(of, name) => !matches!( self.bound(of).pat_parent[name.idx()], crate::bind::PatParent::Param(p) if self.is_resolved_on_request(of, p) ), + // `getTypeForBindingElementParent`, for an element of the pattern. + Query::Pat(of, pattern) => !matches!( + self.bound(of).pat_parent[pattern.idx()], + crate::bind::PatParent::Param(p) if self.is_resolved_on_request(of, p) + && self.returns_before_type_of_every_name(of, pattern) + ), + Query::Return(of, func) => { + self.hir(of)[func].ret.is_some() || self.is_inferred_return_type_requested(of, func) + } _ => true, }; - self.task.file.is_none_or(is_in_time) - || (owner.iter().chain(&self.stack)).any(|&q| { - is_asked_by_check(q) && q.syntax().is_none_or(|(visited, _)| is_in_time(visited)) - }) + (owner.iter().chain(in_progress)).any(|&q| { + is_asked_by_check(q) && q.syntax().is_none_or(|(visited, _)| is_in_time(visited)) + }) + } + + /// Whether `checkVariableLikeDeclaration` `returns_before_type_of_symbol` for every name that + /// `pattern` binds, so that it never asks for the type that `pattern` takes apart. + fn returns_before_type_of_every_name(&self, file: FileId, pattern: PatId) -> bool { + let mut names = Vec::new(); + names_bound_by(self.hir(file), pattern, &mut names); + (names.iter()).all(|&(_, name)| self.returns_before_type_of_symbol(file, name)) + } + + /// `GetDiagnosticsOfAnyProgram`: `Emit`, like a baseline writer, comes after the diagnostics of + /// every file are collected, here after those of the task's file. Whether a diagnostic in + /// `file`, another file that is checked, is one that only they cause: no check asks in time for + /// `owner` or a query in progress. The caller stores no result, so the check of a later file + /// that does ask evaluates it, and reports. + fn is_reported_too_late(&self, owner: Option, file: FileId) -> bool { + self.is_type_checked + && file != NOWHERE.0 + && self.task.file != Some(file) + && self.reports_semantic_errors(file) + && !self.is_asked_by_check_in_time(owner, &self.stack, file) } /// At the end of the task, on its own thread, for `Task::finish`. A query with a task-local key diff --git a/src/sema/check/spans.rs b/src/sema/check/spans.rs index fe5a3c941dcf..d973cec6a6f6 100644 --- a/src/sema/check/spans.rs +++ b/src/sema/check/spans.rs @@ -4,7 +4,7 @@ use super::Checker; use crate::atom::{Atom, known}; -use crate::bind::{ClassOwner, FnOwner, MemberOwner}; +use crate::bind::{FnOwner, MemberOwner}; use crate::hir::{ CaseId, ClassId, EnumMemberId, ExportSpecId, ExprId, ExprKind, File, FileKind, FnBody, FnId, FnKind, IdList, ImportSpecId, MemberId, MemberKind, ModifierKind, Node, NodeData, ParamId, @@ -228,7 +228,10 @@ pub(crate) fn skip_trivia_back(text: &[u8], pos: usize) -> usize { at = open; } if at == before { - return at; + // `isShebangTrivia`: the first line of a file. + let is_in_shebang = text.starts_with(b"#!") + && bun_core::strings::index_of_any(&text[..at], b"\n\r").is_none(); + return if is_in_shebang { 0 } else { at }; } } } @@ -290,6 +293,21 @@ pub(super) fn identifier_end(text: &[u8], at: usize) -> usize { } } +/// `GetErrorRangeForNode`: `SkipTrivia(text, errorNode.Pos())` for the error node whose tokens are +/// `start..end`. One word is taken for an identifier: a caller that reports at another node of one +/// word (a keyword, a type reference, a parameter) skips the trivia itself. +pub(super) fn start_of_error_range(hir: &File, start: u32, end: u32) -> u32 { + if hir.jsdoc_asterisks.is_empty() { + return start; + } + let (text, at) = (&hir.text[..], start as usize); + let is_number = text.get(at).is_some_and(u8::is_ascii_digit); + if !is_number && identifier_end(text, at) == end as usize { + return start; + } + hir.skip_trivia_of_node_at(start) +} + /// The same for a name that may be private. pub(super) fn word_end(text: &[u8], at: usize) -> usize { if text.get(at) == Some(&b'#') { @@ -359,7 +377,7 @@ fn jsx_string_end(text: &[u8], at: usize) -> usize { /// `scanTemplateAndSetTokenValue`, from inside the text of a template: the end of the text, past /// the `` ` `` or the `${`, and whether it is the latter. -fn template_text(text: &[u8], mut at: usize) -> (usize, bool) { +pub(super) fn template_text(text: &[u8], mut at: usize) -> (usize, bool) { loop { match text.get(at) { None => return (text.len(), false), @@ -924,6 +942,13 @@ impl<'a, 's> Spans<'a, 's> { crate::hir::Diagnostic::NO_LENGTH => start, // `getErrorSpanForNode` (parser.go): a missing JSON value ends before it starts. end if end != 0 && (end >= start || self.hir.kind == FileKind::Json) => end, + // `jsErrorAtRange`: so does a missing node, which starts after the trivia it precedes. + end if end != 0 + && self.hir.is_js + && self.skip_trivia(end as usize) == start as usize => + { + end + } // No end was given. _ if is_between_tokens() => start, _ => (self.token(start as usize) as u32).max(start), @@ -986,12 +1011,25 @@ impl<'a, 's> Spans<'a, 's> { PropKey::Computed(e) => { let end = self.expr(e); // `parseComputedPropertyName` - let is_missed = self.byte(self.skip_trivia(end)) != b']'; - if is_missed && self.hir.has_parse_diagnostics { + let mut next = self.skip_trivia(end); + if self + .hir + .jsdoc_asterisks + .binary_search(&(next as u32)) + .is_ok() + { + next = self.skip_trivia(next + 1); + } + // The errors of a JSDoc comment are no parse diagnostics. + if self.byte(next) != b']' + && (self.hir.has_parse_diagnostics || self.hir.is_in_jsdoc(pos as u32)) + { return end; } self.close(end, b']') } + // `createMissingIdentifier`. `""` and `[""]` have the same key. + PropKey::Name(known::empty) if !matches!(self.byte(pos), b'"' | b'\'' | b'[') => pos, _ => self.name(pos), } } @@ -1440,11 +1478,7 @@ impl<'s> Checker<'_, 's> { /// `node.End()` of a class. pub(super) fn end_of_class(&self, file: FileId, class: ClassId) -> u32 { - let hir = self.hir(file); - match self.bound(file).class_owner[class.idx()] { - ClassOwner::Expr(e) => hir[e].end, - ClassOwner::Stmt(s) => hir[s].loc.end, - } + self.bound(file).class_owner[class.idx()].end(self.hir(file)) } /// `node.End()` of `Base` in the `extends` clause of a class (`ExpressionWithTypeArguments`). 0 if there is none. @@ -1544,8 +1578,11 @@ impl<'s> Checker<'_, 's> { } /// `node.End()` of the identifier `name` at `pos`. One that `ScanJSDocToken` returned can - /// contain `-`, which ends the token that `Scan` finds there. + /// contain `-`, which ends the token that `Scan` finds there. A missing identifier is empty. pub(super) fn end_of_identifier_at(&self, file: FileId, name: Atom, pos: u32) -> u32 { + if name == known::empty { + return pos; + } let written = self.hir(file).text.get(pos as usize..).unwrap_or_default(); let name = self.atoms().bytes(name); if !name.is_empty() && written.starts_with(name) { @@ -1629,6 +1666,12 @@ impl Checker<'_, '_> { NodeData::Part(Part::NamedBindings, row) => { self.end_of_node(file, row.with(Part::ImportClause)) } + NodeData::Part(Part::JsxExpression, row) => match hir.data(row) { + NodeData::Expr(e) => { + crate::hir::jsx_expression_around(hir, e).map_or(0, |braces| braces.1) + } + _ => 0, + }, NodeData::Part(Part::Body | Part::Literal, row) => self.end_of_node(file, row), NodeData::Part( Part::Extends | Part::Implements | Part::DeclarationList | Part::CatchClause, @@ -1686,6 +1729,11 @@ impl Checker<'_, '_> { start if start as usize == hir.text.len() => (0, super::explain::NO_LENGTH), start => (start, self.end_of_token_at(file, start)), }, + // `NodeIsMissing(errorNode)`: it is empty, and the trivia that follows is not skipped. + NodeData::Expr(e) if hir.is_missing(node) => { + let pos = hir[e].end.min(hir[e].pos); + (pos, pos) + } NodeData::Expr(e) => ( self.error_start_inside_parentheses(file, e), self.error_end_inside_parentheses(file, e), @@ -1703,6 +1751,14 @@ impl Checker<'_, '_> { NodeData::Part(Part::NamedBindings, _) if hir.name(node).is_some() => { self.get_error_range_for_node(file, hir.name(node)) } + NodeData::Type(_) + | NodeData::Param(_) + | NodeData::TypeParam(_) + | NodeData::TupleElem(_) + | NodeData::Modifier(_) => ( + hir.skip_trivia_of_node_at(hir.start(node)), + self.end_of_node(file, node), + ), _ => (hir.start(node), self.end_of_node(file, node)), } } diff --git a/src/sema/check/symbols.rs b/src/sema/check/symbols.rs index a5ae588a65c5..8ba089b93643 100644 --- a/src/sema/check/symbols.rs +++ b/src/sema/check/symbols.rs @@ -5,7 +5,7 @@ use super::context::{IncludePatternInType, ReportErrors}; use super::decl::declarations_of; use super::mapped::AccessNode; use super::related::Place; -use super::shape::SpreadSymbolOptions; +use super::shape::{SpreadSymbolOptions, assignment_declaration}; use super::*; use crate::bind::{Decl, FnOwner, Parent, PatParent, ScopeId, UNREACHABLE}; use crate::program::{EntityNameLookup, SymbolTable}; @@ -22,12 +22,23 @@ pub(super) struct WideningContext<'p> { widened_types: FxHashMap, } +/// The arguments of `getSymbolFlagsEx`. +#[derive(Copy, Clone, Default)] +pub(super) struct ExcludedMeanings { + /// `excludeTypeOnlyMeanings` + pub(super) type_only: bool, + /// `excludeLocalMeanings` + pub(super) local: bool, +} + /// What `resolveAlias` gives. #[derive(Copy, Clone, PartialEq, Eq)] pub(super) enum AliasTarget { Symbol(Sym), - /// A property has no `Sym`: its owner type (`never`: none), its name, its type. - Property(TypeId, Atom, TypeId), + /// A property has no `Sym`: its owner type (`never`: none), its name, and its type where + /// finding it has resolved that. `None`: `resolveAlias` does not ask for it, see + /// `type_of_alias_target`. + Property(TypeId, Atom, Option), /// `unknownSymbol` Unknown, } @@ -54,7 +65,7 @@ impl EntityNameLookup for Checker<'_, '_> { /// The symbol tables have the target, unless there is a symbol to combine. fn resolve_alias(&mut self, alias: Sym) -> Option { - let combined = self.combined_symbol_of_alias(alias); + let combined = self.combined_symbol_of_resolved_alias(alias); combined.or_else(|| self.files().resolve_alias(alias)) } } @@ -109,7 +120,14 @@ impl Iter3 { self.y.is_some() || self.r.is_some() || self.n.is_some() } - fn all(ty: TypeId) -> Iter3 { + /// `IterationTypes{c.anyType, c.anyType, c.anyType}`, whichever `any` the type `found` is. + /// What is not resolved here stays so. + fn any(found: TypeId) -> Iter3 { + let ty = if found == TypeId::UNRESOLVED { + found + } else { + TypeId::ANY + }; Iter3 { y: Some(ty), r: Some(ty), @@ -126,6 +144,9 @@ pub(super) enum IterationUse { ForAwaitOf, Spread, Destructuring, + /// `IterationUseDestructuring` from `getTypeOfDestructuredArrayElement` and + /// `getTypeOfDestructuredSpreadExpression`, which pass no `errorNode`. + DestructuringInFlow, YieldStar, AsyncYieldStar, GeneratorReturnType, @@ -181,6 +202,7 @@ impl IterationUse { IterationUse::Destructuring => Some(2765), IterationUse::YieldStar | IterationUse::AsyncYieldStar => Some(2766), IterationUse::Element + | IterationUse::DestructuringInFlow | IterationUse::GeneratorReturnType | IterationUse::AsyncGeneratorReturnType => None, } @@ -249,6 +271,27 @@ impl<'p, 's> Checker<'p, 's> { if let Some(known) = self.p.symbol_types.get(&self.task, &sym) { return known; } + // `getTypeOfVariableOrParameterOrPropertyWorker`, "Handle prototype property": before + // `pushTypeResolution`, and after the test for an accessor in `getTypeOfSymbol`. + if !flags.intersects(SymFlags::ACCESSOR) + && self.is_prototype_symbol(sym) + && let Some(class) = self.files().parent_of_symbol(sym) + { + return self.get_type_of_prototype_property(class); + } + } + // `getSymbol` and `symbolIsValue` find an alias by `getSymbolFlags`, which resolves it: it + // has its `aliasTarget` before `getTypeOfAlias` pushes a resolution. Nothing finds + // `export=` that way (`resolveExportByName`). + if flags.contains(SymFlags::ALIAS) + && !flags.intersects(SymFlags::VALUE) + && self.files().symbol(sym).name != known::export_equals + && !self.is_resolving(Query::Symbol(sym)) + { + self.resolve_alias(sym); + if let Some(known) = self.p.symbol_types.get(&self.task, &sym) { + return known; + } } // `checkCallExpression` checks the descriptor of `Object.defineProperty(f, "name", // descriptor)` before anything requests the type of `name`: the text @@ -403,29 +446,16 @@ impl<'p, 's> Checker<'p, 's> { self.report_circularity_error(owner, (file, start, end), name, ty, false); } Some((file, Decl::Expando(declaration) | Decl::ThisProperty(declaration))) => { - let hir = self.hir(file); - let range = |c: &Self, e: ExprId| { - ( - file, - c.start_inside_parentheses(file, e), - c.end_inside_parentheses(file, e), - ) - }; - // `GetNonAssignedNameOfDeclaration`: for `f["a"] = e` and `Object.defineProperty(f, - // "a", d)` the `"a"`, as source text. - let named = match hir[declaration].kind { - ExprKind::Assign { target, .. } => match hir[target].kind { - ExprKind::Index { index, .. } => Some(index), - _ => None, - }, - ExprKind::Call(call) => hir.ids(hir[call].args).nth(1), - _ => None, - }; - let name = match named.map(|named| range(self, named)) { - Some((_, start, end)) => Arg::Bytes(&hir.text[start as usize..end as usize]), + let written = self.name_of_assignment_declaration(file, declaration); + let name = match &written { + Some(written) => Arg::Bytes(written), None => Arg::Atom(self.files().symbol(sym).name), }; - let at = range(self, declaration); + let at = ( + file, + self.start_inside_parentheses(file, declaration), + self.end_inside_parentheses(file, declaration), + ); self.report_circularity_error(owner, at, name, ty, false); } _ => { @@ -474,25 +504,45 @@ impl<'p, 's> Checker<'p, 's> { /// The end of `getTypeOfAlias`, where `popTypeResolution` finds the cycle: /// `reportCircularityError(core.OrElse(exportSymbol, symbol))`. fn report_circularity_error_of_alias(&mut self, alias: Sym) { - let owner = Query::Symbol(alias); - // `getTargetOfAliasDeclaration`, which does not resolve an alias it finds. - let export_symbol = match self.files().alias_links(alias).immediate_target { - Some(target) => AliasTarget::Symbol(target), - None => self.resolve_alias(alias), - }; - match export_symbol { - AliasTarget::Symbol(symbol) => self.report_circularity_error_of_symbol(owner, symbol), - AliasTarget::Property(..) => { - if let Some(prop) = self.property_of_alias(alias) + let (owner, files) = (Query::Symbol(alias), self.files()); + match self.target_of_alias_declaration(alias) { + AliasTarget::Property(object, name, _) => { + if let Some(prop) = self.property_of_alias_target(object, name) && let Some(declaration) = self.value_declaration_of_prop(prop) + && self.is_cycle_found_in_time(declaration.0) { self.report_circularity_error_at(owner, declaration, Arg::Prop(prop)); } } - AliasTarget::Unknown => self.report_circularity_error_of_symbol(owner, alias), + export_symbol => { + let symbol = export_symbol.symbol().unwrap_or(alias); + let declaration = (files.value_declaration(symbol)) + .or_else(|| files.declaration_of_alias_symbol(symbol)); + if declaration.is_some_and(|(file, _)| self.is_cycle_found_in_time(file)) { + self.report_circularity_error_of_symbol(owner, symbol); + } + } } } + /// Whether one checker, which visits the files in program order, finds the cycle of the frame + /// that `leave` has just popped before it collects the diagnostics of `file`. The check of a + /// file comes to the same cycle only from a query that is around all of it: from none above the + /// lowest frame that is circular. `is_reported_in_time` takes every frame. + fn is_cycle_found_in_time(&self, file: FileId) -> bool { + let Some(start) = self.frames.iter().position(|frame| frame.circular) else { + return true; + }; + let is_in_time = |visited: FileId| self.is_checked_no_later_than(visited, file); + self.task.checker_count != 0 + || self.task.file.is_none_or(is_in_time) + || self.stack[..=start].iter().any(|&q| match q { + // `checkAliasSymbol` + Query::AliasTarget(alias) => is_in_time(alias.file), + _ => q.syntax().is_none_or(|(visited, _)| is_in_time(visited)), + }) + } + /// `reportCircularityError` fn report_circularity_error_of_symbol(&mut self, owner: Query, symbol: Sym) { let files = self.files(); @@ -527,7 +577,7 @@ impl<'p, 's> Checker<'p, 's> { } /// `declaration.Type()` - fn type_node_of_declaration(&self, file: FileId, declaration: Decl) -> TypeNodeId { + pub(super) fn type_node_of_declaration(&self, file: FileId, declaration: Decl) -> TypeNodeId { let hir = self.hir(file); match declaration { Decl::Var(pat) | Decl::Param(pat) => self.type_annotation_of_pat(file, pat), @@ -653,6 +703,7 @@ impl<'p, 's> Checker<'p, 's> { { return false; } + self.note_circular_before_parameter_symbol(file, pat); let stored = self.cycle_result(); self.note_result(Query::Pat(file, pat)); self.note_result(Query::ParameterSymbol(file, pat)); @@ -662,6 +713,17 @@ impl<'p, 's> Checker<'p, 's> { true } + /// `reportCircularityError` gives the name `pat` its type. See + /// `circular_before_parameter_symbol`. + fn note_circular_before_parameter_symbol(&mut self, file: FileId, pat: PatId) { + if let PatParent::Param(p) = root_declaration(self.bound(file), pat) + && self.is_resolved_on_request(file, p) + && !self.is_parameter_symbol_resolved(file, p) + { + self.circular_before_parameter_symbol.insert((file, pat)); + } + } + /// `isParameterOfContextSensitiveSignature`, where `GetRootDeclaration` is the parameter `p`. pub(super) fn is_parameter_of_context_sensitive_signature( &self, @@ -692,7 +754,9 @@ impl<'p, 's> Checker<'p, 's> { // `combineValueAndTypeSymbols` has the type of the value. if let Some((alias, is_combined)) = self.files().alias_of_transient_symbol(sym) && let Some(ty) = if is_combined { - self.symbol_from_variable(alias).map(|found| found.2) + self.symbol_from_variable(alias).map(|(object, name)| { + self.type_of_alias_target(AliasTarget::Property(object, name, None)) + }) } else { self.type_of_namespace_import(alias) } @@ -816,18 +880,6 @@ impl<'p, 's> Checker<'p, 's> { } } } - // `bindClassLikeDeclaration`: the `prototype` of a class is among its exports. - let name = self.files().symbol(sym).name; - if flags.intersects(SymFlags::CLASS_MEMBER) - && let Some(class) = self.files().parent_of_symbol(sym) - && self.files().flags(class).contains(SymFlags::CLASS) - && self.files().export(class, name) == Some(self.files().canonical(sym)) - { - let statics = self.type_of_class_value(class); - return self - .type_of_property(statics, name) - .unwrap_or(TypeId::ERROR); - } if !flags.intersects(SymFlags::VALUE) { // A symbol that is not a value has the error type. return TypeId::ERROR; @@ -835,38 +887,24 @@ impl<'p, 's> Checker<'p, 's> { TypeId::UNRESOLVED } - /// `getTypeOfVariableOrParameterOrPropertyWorker`, `case KindBinaryExpression, KindCallExpression`. `None`: no assignment declares `sym`. + /// `getTypeOfVariableOrParameterOrPropertyWorker`, `case KindBinaryExpression, KindCallExpression`. `None`: + /// `symbol.ValueDeclaration` is neither. fn type_of_assignment_declarations(&mut self, sym: Sym) -> Option { - let (mut first_expando, mut first_export) = (None, None); + let files = self.files(); // Every class, function and enum reaches this point: late binding only adds to symbols that // assignments declare. - let declarations = match self.files().flags(sym).contains(SymFlags::ASSIGNMENT) { - true => self.declarations_of_property(sym), - false => self.files().decls_of(sym), - }; - for &(file, decl) in declarations.iter() { - match decl { - Decl::Expando(e) | Decl::ThisProperty(e) if file == sym.file => { - first_expando = first_expando.or(Some(e)); + let (value_declaration, declarations) = + match files.flags(sym).contains(SymFlags::ASSIGNMENT) { + true => { + let (_, value_declaration, declarations) = self.merged_symbol_of_property(sym); + (value_declaration, declarations) } - Decl::ModuleExports(e) | Decl::ExportsProperty(e) if file == sym.file => { - first_export = first_export.or(Some(e)); - } - _ => {} - } - } - let name = self.files().symbol(sym).name; - // `SetValueDeclaration`: an assignment yields to any other value declaration. - let others = SymFlags::VALUE.difference(SymFlags::PROPERTY); - let value_declaration = match first_expando { - Some(first) if !self.files().flags(sym).intersects(others) => first, - _ => self - .commonjs_value_declaration(self.files().symbol(sym)) - .or(first_export)?, - }; + false => (files.value_declaration(sym), files.decls_of(sym)), + }; + let (file, value_declaration) = assignment_declaration(value_declaration?)?; Some(self.get_widened_type_for_assignment_declaration( - sym.file, - name, + file, + files.symbol(sym).name, &declarations, value_declaration, )) @@ -874,16 +912,35 @@ impl<'p, 's> Checker<'p, 's> { /// `getTypeOfAlias` pub(super) fn type_of_alias(&mut self, sym: Sym) -> TypeId { - match self.resolve_alias(sym) { - AliasTarget::Symbol(target) if target != sym => self.type_of_symbol(target), - AliasTarget::Property(_, _, ty) => ty, - _ => TypeId::ERROR, + let target_symbol = self.resolve_alias(sym); + // `exportSymbol`: what it asks for is resolved from here on, also where `resolveAlias` was + // refused. `report_circularity_error_of_alias` asks for the symbol itself. + self.target_of_alias_declaration(sym); + if target_symbol == AliasTarget::Unknown { + self.check_export_symbol_of_alias(sym); + } + match target_symbol { + AliasTarget::Symbol(target) if target == sym => TypeId::ERROR, + target => self.type_of_alias_target(target), } } /// `resolveAlias`. `Files::alias_links` has `getTargetOfAliasDeclaration` as far as it can be /// resolved by name. The part that needs types is added here. pub(super) fn resolve_alias(&mut self, alias: Sym) -> AliasTarget { + self.resolve_alias_ex(alias, false) + } + + /// `getTargetOfAliasDeclaration(getDeclarationOfAliasSymbol(alias))` where `resolveAlias` is + /// not the caller: it pushes no resolution, asks again whatever `aliasTarget` is, and does not + /// resolve an alias that it finds. `Unknown`: nil. + fn target_of_alias_declaration(&mut self, alias: Sym) -> AliasTarget { + self.resolve_alias_ex(alias, true) + } + + /// `dont_resolve_alias`: see `target_of_alias_declaration`. + #[inline(never)] + fn resolve_alias_ex(&mut self, alias: Sym, dont_resolve_alias: bool) -> AliasTarget { let files = self.files(); let mut at = alias; // The aliases from `alias` to `at`. `resolveIndirectionAlias`: each is being resolved while @@ -895,10 +952,12 @@ impl<'p, 's> Checker<'p, 's> { return AliasTarget::Symbol(at); } let links = files.alias_links(at); - if links.is_circular { - return AliasTarget::Unknown; + if !dont_resolve_alias { + if links.is_circular { + return AliasTarget::Unknown; + } + resolving.push(at); } - resolving.push(at); if let Some(module) = self.module_of_namespace_import_or_export(at) { if !self.enter_alias_targets(&resolving) { return AliasTarget::Unknown; @@ -911,39 +970,53 @@ impl<'p, 's> Checker<'p, 's> { return created; } } - let immediate_target = match self.target_of_module_default(&resolving) { + let immediate_target = match self.target_of_module_default(at, &resolving) { Some(AliasTarget::Symbol(target)) => Some(target), Some(target) => return target, None => links.immediate_target, }; - let Some(next) = immediate_target else { - let before = &resolving[..resolving.len() - 1]; - if !self.enter_alias_targets(before) { + // `symbolFromVariable` of `getExternalModuleMember`, where the result depends on it: + // the tables have no `symbolFromModule`, or one to combine it with. + let combined = files.combined_symbol(at); + let mut symbol_from_variable = None; + if (immediate_target.is_none() || combined.is_some()) + && let Some((module, name)) = self.imported_from_export_equals(at) + { + if !self.enter_alias_targets(&resolving) { return AliasTarget::Unknown; } - let symbol_from_variable = self.symbol_from_variable(at); - if !self.leave_alias_targets(before) { + let object = self.owner_of_exported_property(module, name); + if !self.leave_alias_targets(&resolving) { return AliasTarget::Unknown; } - let symbol_from_module = self.synthetic_default_from_module(&resolving); + symbol_from_variable = object.map(|object| (object, name)); + } + let Some(next) = immediate_target else { + let symbol_from_module = self.synthetic_default_from_module(at, &resolving); // `combineValueAndTypeSymbols`: the property is the value. The `default` that // `createDefaultPropertyWrapperForModule` makes is an alias without a declaration: // combined with the `export =`, it resolves as that does. - let symbol_from_variable = symbol_from_variable.filter(|&(object, ..)| { + let symbol_from_variable = symbol_from_variable.filter(|&(object, _)| { symbol_from_module.is_none() || !self.has_default_property_wrapper(object) }); - if let Some((object, name, ty)) = symbol_from_variable { - return AliasTarget::Property(object, name, ty); + if let Some((object, name)) = symbol_from_variable { + return AliasTarget::Property(object, name, None); } let Some(next) = symbol_from_module else { - return self.resolved_symbol_of_alias_like_expression(&resolving); + return self.resolved_symbol_of_alias_like_expression(at, &resolving); }; + if dont_resolve_alias { + return AliasTarget::Symbol(next); + } at = next; continue; }; - if let Some(combined) = self.combined_symbol_of_alias(at) { + if let (Some(combined), Some(_)) = (combined, symbol_from_variable) { return AliasTarget::Symbol(combined); } + if dont_resolve_alias { + return AliasTarget::Symbol(next); + } // As in `aliasTarget` of the symbol links: a target resolved while symbols were merged is the symbol that // existed at that time. if next == at || !files.is_non_local_alias(next) { @@ -985,20 +1058,27 @@ impl<'p, 's> Checker<'p, 's> { pub(super) fn type_of_alias_target(&mut self, symbol: AliasTarget) -> TypeId { match symbol { AliasTarget::Symbol(symbol) => self.type_of_symbol(symbol), - AliasTarget::Property(_, _, ty) => ty, + AliasTarget::Property(_, _, Some(ty)) => ty, + AliasTarget::Property(object, name, None) => { + match self.get_property_of_type_ex(object, name, true) { + Some((prop, mapper)) => self.type_of_prop(prop, mapper), + None => TypeId::ERROR, + } + } AliasTarget::Unknown => TypeId::ERROR, } } /// The end of `getTargetOfAliasLikeExpression`: in `export = e`, `export default e`, /// `module.exports = e` and `exports.x = e`, an entity name `e` that `resolveEntityName` does - /// not resolve aliases the `resolvedSymbol` that checking `e` records. For the last of the - /// aliases `resolving` (`enter_alias_targets`). - fn resolved_symbol_of_alias_like_expression(&mut self, resolving: &[Sym]) -> AliasTarget { - let Some(&sym) = resolving.last() else { - return AliasTarget::Unknown; - }; - let Some((file, decl)) = self.files().declaration_of_alias_symbol(sym) else { + /// not resolve aliases the `resolvedSymbol` that checking `e` records. For `alias`, the last + /// of the aliases `resolving` (`enter_alias_targets`). + fn resolved_symbol_of_alias_like_expression( + &mut self, + alias: Sym, + resolving: &[Sym], + ) -> AliasTarget { + let Some((file, decl)) = self.files().declaration_of_alias_symbol(alias) else { return AliasTarget::Unknown; }; let hir = self.hir(file); @@ -1030,25 +1110,33 @@ impl<'p, 's> Checker<'p, 's> { /// `e` that `resolveEntityName` does not resolve. fn resolved_symbol_of_checked_expression(&mut self, file: FileId, e: ExprId) -> AliasTarget { let hir = self.hir(file); + let before = self.non_cacheable_mark(); + let ty = self.check_expression_cached_ex(file, e, CheckMode::empty()); match hir[e].kind { // `argumentsSymbol` is not a property of any type. ExprKind::Ident(name) if name == known::arguments && self.symbol_of_identifier(file, e, name).is_none() => { - AliasTarget::Property(TypeId::NEVER, name, self.type_of_expr(file, e)) + AliasTarget::Property(TypeId::NEVER, name, Some(ty)) } // `checkPropertyAccessExpressionOrQualifiedName` records a property, never an index // signature, and nothing for `any`. ExprKind::Dot { obj, name, .. } => { - let object = self.type_of_expr(file, obj); + // `getResolvedSymbolOrNil` evaluates nothing. The type of `obj` is not kept if it depends on a resolution in + // progress, and then it is `any` or an error, for which nothing is recorded. + let object = match self.cached_type_of_expr(file, obj) { + Some(object) => object, + None if self.non_cacheable_mark() != before => return AliasTarget::Unknown, + None => self.type_of_expr(file, obj), + }; // `checkNonNullExpression` let object = self.non_null_type(object); if self.is_any(object) { return AliasTarget::Unknown; } if let Some((property, _)) = self.declared_property(object, name) { - return AliasTarget::Property(object, name, property); + return AliasTarget::Property(object, name, Some(property)); } // `getPropertyOfTypeEx` also finds the members of `Object` and `Function`, except on a `const enum` object. let apparent = self.reduced_apparent_type(object); @@ -1058,7 +1146,8 @@ impl<'p, 's> Checker<'p, 's> { && members.resolved.prop(name).is_none() && let Some((prop, mapper)) = self.property_in_type(apparent, &members, name) { - return AliasTarget::Property(object, name, self.type_of_prop(prop, mapper)); + let ty = self.type_of_prop(prop, mapper); + return AliasTarget::Property(object, name, Some(ty)); } AliasTarget::Unknown } @@ -1066,42 +1155,96 @@ impl<'p, 's> Checker<'p, 's> { } } - /// `getExternalModuleMember`: `combineValueAndTypeSymbols(symbolFromVariable, - /// symbolFromModule)`, where it creates a symbol. - pub(super) fn combined_symbol_of_alias(&mut self, alias: Sym) -> Option { - let combined = self.files().combined_symbol(alias)?; - self.symbol_from_variable(alias).map(|_| combined) + /// `resolveAlias(alias)`, where `combineValueAndTypeSymbols` has created it, for `alias` or for + /// an alias on the chain to its target. + pub(super) fn combined_symbol_of_resolved_alias(&mut self, alias: Sym) -> Option { + let files = self.files(); + if !files.has_symbol_to_combine(alias) { + return None; + } + let target = self.resolve_alias(alias).symbol()?; + let (_, is_combined) = files.alias_of_transient_symbol(target)?; + is_combined.then_some(target) } - /// `getSymbolFlags`. The symbol tables compute and cache it, unless types are needed: where the - /// alias chain does not resolve to a symbol, or there is a symbol to combine. + /// `getSymbolFlags` pub(super) fn get_symbol_flags(&mut self, sym: Sym) -> SymFlags { + let kept = self.files().symbol_flags(sym); + self.symbol_flags_by_types(sym, kept, ExcludedMeanings::default()) + } + + /// `getSymbolFlagsEx` + pub(super) fn get_symbol_flags_ex( + &mut self, + symbol: Sym, + excluded: ExcludedMeanings, + ) -> SymFlags { + let files = self.files(); + let kept = files.symbol_flags_ex(symbol, excluded.type_only, excluded.local); + self.symbol_flags_by_types(symbol, kept, excluded) + } + + /// `getSymbolFlagsEx`. `kept`: what the symbol tables compute and cache. That is the result, + /// unless types are needed: where the alias chain does not resolve to a symbol, or there is a + /// symbol to combine on it. `combineValueAndTypeSymbols` leaves a `typeSymbol` that is a value. + fn symbol_flags_by_types( + &mut self, + mut symbol: Sym, + kept: SymFlags, + excluded: ExcludedMeanings, + ) -> SymFlags { let files = self.files(); - let kept = files.symbol_flags(sym); - if kept != SymFlags::all() && files.combined_symbol(sym).is_none() { + if kept != SymFlags::all() + && (kept.intersects(SymFlags::VALUE) || !files.has_symbol_to_combine(symbol)) + { return kept; } - self.flags_of_alias_target(sym) - .map_or(SymFlags::all(), |of_target| files.flags(sym) | of_target) + let mut flags = match excluded.local { + true => SymFlags::empty(), + false => files.flags(symbol), + }; + let mut seen_symbols: SmallVec<[Sym; 4]> = SmallVec::new(); + while files.flags(symbol).contains(SymFlags::ALIAS) + && !(excluded.type_only && files.alias_links(symbol).type_only_declaration.is_some()) + { + seen_symbols.push(symbol); + match self.symbol_of_alias_target(symbol) { + Ok(target) if seen_symbols.contains(&target) => break, + Ok(target) => symbol = target, + Err(of_target) => return flags | of_target, + } + flags |= files.flags(symbol); + } + flags } - /// `getSymbolFlags(resolveAlias(alias))`. `None`: `unknownSymbol`. - pub(super) fn flags_of_alias_target(&mut self, alias: Sym) -> Option { + /// `getExportSymbolOfValueSymbolIfExported(resolveAlias(alias))`. `Err`: its flags, where it is + /// no symbol of the tables: a property that none declares, or `unknownSymbol`, which stands + /// for every meaning. + fn symbol_of_alias_target(&mut self, alias: Sym) -> Result { let files = self.files(); match self.resolve_alias(alias) { AliasTarget::Symbol(target) => { - Some(files.symbol_flags(files.export_symbol_of_value_symbol_if_exported(target))) + Ok(files.export_symbol_of_value_symbol_if_exported(target)) } // An export of a namespace or a module is a property of its type, and has the meaning // it has there. - AliasTarget::Property(..) => Some(match self.property_of_alias(alias) { + AliasTarget::Property(..) => match self.property_of_alias(alias) { Some(&Prop { source: PropSource::Symbol(member), .. - }) => files.symbol_flags(member), - _ => SymFlags::PROPERTY, - }), - AliasTarget::Unknown => None, + }) => Ok(member), + _ => Err(SymFlags::PROPERTY), + }, + AliasTarget::Unknown => Err(SymFlags::all()), + } + } + + /// `getSymbolFlags(resolveAlias(alias))`. `None`: `unknownSymbol`. + pub(super) fn flags_of_alias_target(&mut self, alias: Sym) -> Option { + match self.symbol_of_alias_target(alias) { + Ok(target) => Some(self.get_symbol_flags(target)), + Err(of_target) => (of_target != SymFlags::all()).then_some(of_target), } } @@ -1154,6 +1297,11 @@ impl<'p, 's> Checker<'p, 's> { let AliasTarget::Property(object, name, _) = self.resolve_alias(sym) else { return None; }; + self.property_of_alias_target(object, name) + } + + /// The property that `AliasTarget::Property(object, name, _)` stands for. + fn property_of_alias_target(&mut self, object: TypeId, name: Atom) -> Option<&'p Prop<'p>> { // `getReducedApparentType` let apparent = self.reduced_apparent_type(object); Some(self.prop_ref(apparent, name)?.0) @@ -1183,9 +1331,14 @@ impl<'p, 's> Checker<'p, 's> { // No symbol is created for the copy of a target that has none itself: `export = a`, where // `a` resolves to a property. if let Some(ty) = self.type_of_namespace_import(alias) { + // `getSpreadType(typ, { default })` runs while `alias` is being resolved: + // `getSpreadSymbol` asks for the type of every property that it recreates. + if self.has_default_property_wrapper(ty) { + let _ = self.members(ty); + } return Some(match files.module_clone(alias) { Some(clone) => AliasTarget::Symbol(clone), - None => AliasTarget::Property(TypeId::NEVER, files.symbol(alias).name, ty), + None => AliasTarget::Property(TypeId::NEVER, files.symbol(alias).name, Some(ty)), }); } // For another `import * as ns`, through which the `export =` of `module` resolves. @@ -1225,17 +1378,8 @@ impl<'p, 's> Checker<'p, 's> { let value = symbol .symbol() .unwrap_or_else(|| files.module_value(module)); - // Under a Node module mode, an ECMAScript module imports a file. - let is_file_to_node = files - .symbol(module) - .decls - .iter() - .any(|d| matches!(d, Decl::File)) - && files.options.module.is_node() - && files.module(file).is_esm; - // `getTypeWithSyntheticDefaultOnly`, `isOnlyImportableAsDefault`: in that case a JSON file - // has only a default export. - if is_file_to_node && files.is_json_module(module.file) { + // `getTypeWithSyntheticDefaultOnly` + if files.is_only_importable_as_default(file, module) { return Some(self.intern(TypeData::Anon { origin: Origin::Namespace { module: value, @@ -1359,10 +1503,10 @@ impl<'p, 's> Checker<'p, 's> { (files.flags(value).intersects(only_the_type_tells)).then_some(module) } - /// `getTargetOfModuleDefault`, without its errors, for the last of the aliases `resolving` - /// (`enter_alias_targets`). `None`: the tables have its target (`module_of_default_import`). - fn target_of_module_default(&mut self, resolving: &[Sym]) -> Option { - let &alias = resolving.last()?; + /// `getTargetOfModuleDefault`, without its errors, for `alias`, the last of the aliases + /// `resolving` (`enter_alias_targets`). `None`: the tables have its target + /// (`module_of_default_import`). + fn target_of_module_default(&mut self, alias: Sym, resolving: &[Sym]) -> Option { let module = self.module_of_default_import(alias)?; let (file, files) = (alias.file, self.files()); if !self.enter_alias_targets(resolving) { @@ -1390,11 +1534,8 @@ impl<'p, 's> Checker<'p, 's> { let export_equals = files.export(module, known::export_equals); return export_equals.map(AliasTarget::Symbol); } - // `resolveAlias` finds the property. Its type is for `getTypeOfAlias`. Some(match export_symbol { - Some((object, prop, mapper)) => { - AliasTarget::Property(object, prop.name, self.type_of_prop(prop, mapper)) - } + Some((object, prop, _)) => AliasTarget::Property(object, prop.name, None), None => AliasTarget::Unknown, }) } @@ -1438,31 +1579,29 @@ impl<'p, 's> Checker<'p, 's> { /// `symbolFromVariable` of `getExternalModuleMember`: `import { a } from "m"`, `export { a } /// from "m"` and `const { a } = require("m")` name a property of the value when `m` has `export - /// = value`. Returns the type of the value, `a`, and the type of the property. - pub(super) fn symbol_from_variable(&mut self, sym: Sym) -> Option<(TypeId, Atom, TypeId)> { + /// = value`. Returns the type of the value and `a`. It pushes no resolution, and finds the + /// property whatever `aliasTarget` of `sym` has become. + pub(super) fn symbol_from_variable(&mut self, sym: Sym) -> Option<(TypeId, Atom)> { let (module, name) = self.imported_from_export_equals(sym)?; - if !self.enter_alias_target(sym) { - return None; - } + let object = self.owner_of_exported_property(module, name)?; + Some((object, name)) + } + + /// The type of the value of `module`, which has `export = value`, if that has a property + /// `name`. + fn owner_of_exported_property(&mut self, module: Sym, name: Atom) -> Option { let value = self.resolve_external_module_symbol(module); let ty = self.type_of_alias_target(value); - let property = match self.is_any(ty) { - true => None, - false => self.get_property_of_type_ex(ty, name, true), - }; - if !self.leave_alias_target(sym) { + if self.is_any(ty) { return None; } - // `resolveAlias` finds the property. Its type is for `getTypeOfAlias`. - let (prop, mapper) = property?; - Some((ty, name, self.type_of_prop(prop, mapper))) + self.get_property_of_type_ex(ty, name, true).map(|_| ty) } /// `symbolFromModule` of `getExternalModuleMember` where the module exports no `default`, for - /// the last of the aliases `resolving` (`enter_alias_targets`). Only a binding element comes - /// there with that name: `const { default: d } = require("m")`. - fn synthetic_default_from_module(&mut self, resolving: &[Sym]) -> Option { - let &alias = resolving.last()?; + /// `alias`, the last of the aliases `resolving` (`enter_alias_targets`). Only a binding element + /// comes there with that name: `const { default: d } = require("m")`. + fn synthetic_default_from_module(&mut self, alias: Sym, resolving: &[Sym]) -> Option { let (file, files) = (alias.file, self.files()); let mut declarations = files.symbol(alias).decls.iter(); let (spec, mode, name) = declarations.find_map(|&decl| match decl { @@ -1731,7 +1870,7 @@ impl<'p, 's> Checker<'p, 's> { let at = self.place_of_signature_declaration(file, func); let widened = self.get_widened_type(ty); let is_yield = matches!(kind, WideningKind::GeneratorYield); - if f.name.is_some() || matches!(f.kind, FnKind::Method | FnKind::Getter) { + if f.name.is_some() || matches!(f.kind, FnKind::Method | FnKind::Getter | FnKind::Setter) { let name = self.declaration_name_at(file, at.1); let code = if is_yield { 7055 } else { 7010 }; self.error_at(at, code, &[Arg::Bytes(&name), Arg::Type(widened)]); @@ -1795,17 +1934,14 @@ impl<'p, 's> Checker<'p, 's> { return; }; // A missing parameter has an empty span. - let node = (file, hir[p].pos, self.end_of_param(file, p).max(hir[p].pos)); + let end = self.end_of_param(file, p).max(hir[p].pos); + let node = (file, hir.skip_trivia_of_node_at(hir[p].pos), end); let (func, is_rest) = (bound.param_fn[p.idx()], hir[p].flags.contains(Flags::REST)); - let is_signature = matches!(hir[func].kind, FnKind::CallSignature | FnKind::FunctionType) - || hir[func].kind == FnKind::Method - && matches!(bound.fns[func.idx()].owner, FnOwner::Member(m) if !matches!(bound.member_owner[m.idx()], crate::bind::MemberOwner::Class(_))); - if let PatKind::Ident(written) = hir[pat].kind - && is_signature + if let Some(written) = self.identifier_of_signature_parameter(file, p) && self.is_name_of_a_type(file, func, written) { // A leading `this` parameter is counted, and is not among `params`. - let position = p.0 - hir[func].params.start + hir[func].this_ty(hir).is_some() as u32; + let position = p.0 - hir[func].params.start + hir[func].this_param.is_some() as u32; let atoms = &self.atoms(); let new_name = [b"arg", atoms.bytes(self.number_name(position as f64))].concat(); let array_name = match name { @@ -1825,9 +1961,8 @@ impl<'p, 's> Checker<'p, 's> { } /// `isObjectLiteralType`: whether `ty` is the type of an object literal expression, fresh or - /// not, as opposed to the type of a declaration initialized with one. The type implied by a - /// binding pattern is marked too, but no expression has that type - /// (`getTypeFromObjectBindingPattern`). + /// not, as opposed to the type of a declaration initialized with one, or the type implied by a + /// binding pattern (`getTypeFromObjectBindingPattern`). #[inline] pub fn is_object_literal_type(&self, ty: TypeId) -> bool { super::relate::is_object_literal_kind(self.data(ty)) @@ -1839,17 +1974,21 @@ impl<'p, 's> Checker<'p, 's> { super::relate::is_fresh_object_literal_kind(self.data(ty)) } - /// An object literal without spreads: it has exactly the declared properties. + /// `isObjectLiteralType(t) && t.objectFlags&ObjectFlagsContainsSpread == 0`: an object literal + /// without spreads, which has exactly the declared properties. pub fn is_closed_object_literal_type(&self, ty: TypeId) -> bool { match self.data(ty) { TypeData::Anon { origin: Origin::ObjectLiteral(..), .. } => true, - TypeData::Synth(shape) => matches!( - shape.literal, - Literalness::Literal | Literalness::JsxAttributes - ), + TypeData::Synth(shape) => match shape.literal { + Literalness::Literal => true, + // `createJsxAttributesTypeFromAttributesProperty`: whatever an element has, with a + // spread attribute or without, goes through `getSpreadType`. + Literalness::JsxAttributes => shape.props.is_empty(), + literal => literal.is_of_pattern(), + }, _ => false, } } @@ -1886,20 +2025,9 @@ impl<'p, 's> Checker<'p, 's> { } match self.data(ty) { TypeData::Intrinsic(_) => return TypeId::ANY, - // Without a context it is interned, which acts as a cache. - TypeData::Anon { - origin: Origin::ObjectLiteral(..), - .. - } => return self.get_widened_type_of_object_literal(ty, context), - // The type implied by a pattern is widened like a literal, into a type that - // `patternForType` does not know. - TypeData::Synth(shape) - if shape.literal.is_of_expression() - || matches!( - shape.literal, - Literalness::Pattern | Literalness::PatternWithComputedNames - ) => - { + // Without a context it is interned, which acts as a cache. The type implied by a + // pattern is widened into a type that `patternForType` does not know. + data if super::relate::is_object_literal_kind(data) => { return self.get_widened_type_of_object_literal(ty, context); } _ => {} @@ -1946,12 +2074,15 @@ impl<'p, 's> Checker<'p, 's> { readonly, } => match self.get_widened_types(elems) { Some(widened) => self.tuple(&widened, flags, *readonly), - // `createTypeReference` does not return the clone of `createArrayLiteralType`. - None if self.types().is_array_literal(ty) => self.intern_key(TypeKey::Tuple { - elems, - flags, - readonly: *readonly, - }), + // `createTypeReference` does not return the clone of `createArrayLiteralType` or + // `getTypeFromArrayBindingPattern`. + None if self.types().is_array_literal(ty) || self.types().is_array_pattern(ty) => { + self.intern_key(TypeKey::Tuple { + elems, + flags, + readonly: *readonly, + }) + } None => ty, }, TypeData::Ref { @@ -2087,14 +2218,14 @@ impl<'p, 's> Checker<'p, 's> { let widened = match self.data(ty) { TypeData::Anon { origin: - Origin::ObjectLiteral(file, e, is_js_literal, of_declaration, object_flags, _), + Origin::ObjectLiteral(file, e, is_js_literal, created_by, object_flags, _), mapper, } => self.intern(TypeData::Anon { origin: Origin::WidenedLiteral( *file, *e, *is_js_literal, - *of_declaration, + *created_by, object_flags.contains(ObjectFlags::NON_INFERRABLE_TYPE), ), mapper: *mapper, @@ -2159,6 +2290,7 @@ impl<'p, 's> Checker<'p, 's> { if let TypeData::Synth(widened) = self.data(ty) { (shape.spread_of, shape.spread_rank) = (widened.spread_of, widened.spread_rank); shape.has_no_instantiable_symbol = widened.has_no_instantiable_symbol; + shape.pattern_at = widened.pattern_at; if widened.literal == Literalness::Partial { (shape.literal, shape.is_regular) = (Literalness::Partial, true); } @@ -2304,6 +2436,11 @@ impl<'p, 's> Checker<'p, 's> { if let Some(raw) = self.provisional(query) { return TypeId(raw as u32); } + if self.is_flow_loop_or_exhaustive_state_in_progress() + && let Some(ty) = self.recheck_pat_in_flow_loop(file, pat, query) + { + return ty; + } if !self.enter(query) { if !self.found_cycle { return TypeId::UNRESOLVED; @@ -2329,6 +2466,7 @@ impl<'p, 's> Checker<'p, 's> { // `assignParameterType` or `assignBindingElementTypes`, which is in progress below. let mut assigned = self.assigned_parameters.iter(); if !assigned.any(|&at| self.stack.get(at) == Some(&query)) { + self.note_circular_before_parameter_symbol(file, pat); let stored = self.cycle_result(); // Overwrites the value of an inner evaluation above a `resolution_start` barrier, // if one was stored. @@ -2353,17 +2491,48 @@ impl<'p, 's> Checker<'p, 's> { ty } + /// For a declaration whose name is a pattern, `getTypeForVariableLikeDeclaration` pushes no + /// type resolution and has no re-entrancy guard either: `recheck_in_flow_loop` for `pat`. + fn recheck_pat_in_flow_loop( + &mut self, + file: FileId, + pat: PatId, + query: Query, + ) -> Option { + if self.is_resolution(query) { + return None; + } + let first = self.stack.iter().rposition(|&q| q == query)?; + let pushed_at = self.flow_loop_pushed_since(first)?; + let resolution_start = std::mem::replace(&mut self.resolution_start, self.stack.len()); + let entered = self.enter(query); + self.resolution_start = resolution_start; + if !entered { + return Some(TypeId::UNRESOLVED); + } + self.taint_from(pushed_at); + let ty = self.type_of_pat_uncached(file, pat); + let _ = self.leave(query); + Some(ty) + } + /// Diagnostics reported inside a cycle are dropped with the results that depend on it, and /// `pat` has received its result (`reportCircularityError`) without being evaluated again. tsgo /// continues through the cycle with `any` and reports what it finds, so the walk evaluates it - /// once more. + /// once more, with `links.resolvedType` of the symbol of its parameter as it was. pub(super) fn report_on_circular_pat(&mut self, file: FileId, pat: PatId) { // The caller has just requested the type, so the first read is a hit. let key = (file, pat); let is_circular = (self.p.pat_types.get(&self.task, &key)).is_some_and(|(_, flag)| flag) || self.p.circular_initializers.get(&self.task, &key).is_some(); if is_circular && self.enter(Query::Pat(file, pat)) { + if self.circular_before_parameter_symbol.contains(&key) + && let PatParent::Param(p) = root_declaration(self.bound(file), pat) + { + self.parameter_symbol_taken_as_unresolved = Some((file, p)); + } self.type_of_pat_uncached(file, pat); + self.parameter_symbol_taken_as_unresolved = None; // The frame stores nothing, so its diagnostics do not belong to the entry of `pat_types`. self.settle_reported_without_entry(); let _ = self.leave(Query::Pat(file, pat)); @@ -2392,12 +2561,9 @@ impl<'p, 's> Checker<'p, 's> { } { // The resolutions of the declaration itself are right below the frame of `e`. - let to = self.stack.len() - 1; - let mut below = self.stack[..to].iter(); - let from = below - .rposition(|&q| !self.is_resolution(q)) - .map_or(0, |i| i + 1); - self.quick_initializers.push((from, to)); + let resolutions = self.resolutions_below(self.stack.len() - 1); + self.quick_initializers.push(resolutions); + self.frames[resolutions.1].is_quick_type = true; let quick = self.quick_type_of_expr(file, e); self.quick_initializers.pop(); let _ = self.leave(Query::Expr(file, e)); @@ -2532,8 +2698,23 @@ impl<'p, 's> Checker<'p, 's> { self.type_of_alias(self.files().sym(file, symbol)) } PatParent::Prop(parent, _) | PatParent::Elem(parent, _) => { + // `CheckModeRestBindingElement` goes to the declaration that has the pattern, and + // `getTypeOfInitializer` finds no `links.resolvedType`: no `checkExpressionCached`. + let bound = self.bound(file); + let is_uncached = bound.pat_parent[pat.idx()].has_dot_dot_dot_token(hir) + && matches!( + bound.pat_parent[parent.idx()], + PatParent::Var(_) | PatParent::Param(_) + ); + if is_uncached { + let resolutions = self.resolutions_below(self.stack.len()); + self.quick_initializers.push(resolutions); + } let parent_ty = self.type_for_binding_element_parent(file, pat, parent); let ty = self.type_of_binding_element(file, pat, parent_ty, false); + if is_uncached { + self.quick_initializers.pop(); + } // A destructured value is not widened; the elements extracted from it are, once // bound to a name. if !matches!(hir[pat].kind, PatKind::Ident(_)) { @@ -2558,11 +2739,7 @@ impl<'p, 's> Checker<'p, 's> { parent: PatId, ) -> TypeId { let (hir, bound) = (self.hir(file), self.bound(file)); - let is_rest = match bound.pat_parent[pat.idx()] { - PatParent::Prop(_, prop) => hir[prop].is_rest, - PatParent::Elem(_, elem) => hir[elem].is_rest, - _ => false, - }; + let is_rest = bound.pat_parent[pat.idx()].has_dot_dot_dot_token(hir); // `getTypeForBindingElement` let check_mode = if is_rest { CheckMode::REST_BINDING_ELEMENT @@ -2609,18 +2786,30 @@ impl<'p, 's> Checker<'p, 's> { // `CheckModeRestBindingElement`: for `...rest` the initializer is checked again, // without the pattern causing a type parameter to be abandoned. PatParent::Var(d) if is_rest && hir[d].ty.is_none() && hir[d].init.is_some() => { - match self.type_of_reference_for_rest(file, hir[d].init) { - Some(ty) => ty, - None => self.type_of_pat(file, parent), - } + let ty = self.check_declaration_initializer_for_rest(file, hir[d].init); + self.widen_type_inferred_from_initializer(file, parent, ty) + } + // A binding element whose name is a pattern has no symbol: `getTypeForBindingElement` + // again, and not what `pat_types` has from the resolved type of the parameter. + PatParent::Prop(..) | PatParent::Elem(..) + if self + .parameter_symbol_taken_as_unresolved + .is_some_and(|(of, p)| { + of == file && root_declaration(bound, parent) == PatParent::Param(p) + }) + && self.enter(Query::Pat(file, parent)) => + { + let ty = self.type_of_pat_uncached(file, parent); + let _ = self.leave(Query::Pat(file, parent)); + ty } _ => self.type_of_pat(file, parent), } } /// `getTypeForVariableLikeDeclaration(declaration, false /*includeOptionality*/, checkMode)`, - /// which does not widen, for the parameter `p`: it has no annotation, its name is a pattern, and - /// its function is a declaration or a member of a class, which has no contextual type. + /// which does not widen, for the parameter `p`, which `is_resolved_on_request`: its function + /// has no contextual type. fn type_for_parameter_of_declaration( &mut self, file: FileId, @@ -2630,7 +2819,8 @@ impl<'p, 's> Checker<'p, 's> { let hir = self.hir(file); let func = self.bound(file).param_fn[p.idx()]; if hir[func].kind == FnKind::Setter - && let Some((of, getter)) = self.sibling_accessor(file, func, FnKind::Getter) + && let Some((of, getter)) = + self.sibling_accessor_at_this_moment(file, func, FnKind::Getter) { return self.return_type_of_fn(of, getter); } @@ -2641,25 +2831,15 @@ impl<'p, 's> Checker<'p, 's> { if hir[p].default.is_some() { return self.type_from_param_default(file, p, check_mode); } - self.type_from_binding_pattern_of_param(file, func, p) + self.type_from_binding_pattern_of_param(file, p) .unwrap_or(TypeId::ANY) } /// `getTypeFromBindingPattern(declaration.Name(), false /*includePatternInType*/, true - /// /*reportErrors*/)` for the parameter `p` of `func`. `None` for a plain name. - fn type_from_binding_pattern_of_param( - &mut self, - file: FileId, - func: FnId, - p: ParamId, - ) -> Option { - let report_errors = if self.is_parameter_type_never_requested(file, func, p) { - ReportErrors::No - } else { - ReportErrors::Yes - }; + /// /*reportErrors*/)` for the parameter `p`. `None` for a plain name. + fn type_from_binding_pattern_of_param(&mut self, file: FileId, p: ParamId) -> Option { let pat = self.hir(file)[p].pat; - self.implied_by_pattern(file, pat, IncludePatternInType::No, report_errors) + self.implied_by_pattern(file, pat, IncludePatternInType::No, ReportErrors::Yes) } /// The head of `getBindingElementTypeFromParentType`: the type `pattern` destructures, given @@ -2736,7 +2916,12 @@ impl<'p, 's> Checker<'p, 's> { // other name omits by its type. let (mut omitted, mut keys) = (Vec::new(), Vec::new()); for p in props.iter() { - let PatProp { key, name_kind, .. } = hir[p]; + let PatProp { + key, + name_kind, + key_pos, + .. + } = hir[p]; if hir[p].is_rest { continue; } @@ -2744,21 +2929,28 @@ impl<'p, 's> Checker<'p, 's> { PropKey::Name(name) if !self.is_numeric_name(name) => { omitted.push(name) } - _ => keys - .extend(self.literal_type_from_property_name(file, key, name_kind)), + _ => keys.extend( + self.literal_type_from_property_name(file, key, name_kind, key_pos), + ), } } let keys = self.union(&keys); // `declaration.Symbol()` let symbol = matches!(hir[pat].kind, PatKind::Ident(_)).then_some((file, pat)); - let ty = self.rest_of_object(parent_ty, &omitted, keys, symbol); + let ty = self.rest_of_object(parent_ty, &omitted, keys, symbol, None); return self.with_default(file, pat, ty, prop.default); } let mut access_flags = AccessFlags::EXPRESSION_POSITION; let allow_missing = no_tuple_bounds_check || prop.default.is_some(); access_flags.set(AccessFlags::ALLOW_MISSING, allow_missing); + let PatProp { + key, + name_kind, + key_pos, + .. + } = *prop; let Some(index_type) = - self.literal_type_from_property_name(file, prop.key, prop.name_kind) + self.literal_type_from_property_name(file, key, name_kind, key_pos) else { return TypeId::UNRESOLVED; }; @@ -2810,10 +3002,10 @@ impl<'p, 's> Checker<'p, 's> { if self.is_any(ty) { return ty; } - // "This call also checks that the parentType is in fact an iterable or array". An array or - // a tuple is, so the call is skipped. + // "This call also checks that the parentType is in fact an iterable or array". FOR SPEED: + // an array or a tuple is, as the default library declares them, so the call is skipped. if let Some((pattern, AccessNode::BindingName(file, _), _)) = nodes - && !self.is_array_or_tuple(ty) + && !(self.is_array_or_tuple(ty) && self.is_iterable_by_default_library(ty)) { let pattern = ( file, @@ -2892,13 +3084,14 @@ impl<'p, 's> Checker<'p, 's> { reduced == TypeId::UNKNOWN || !self.is_valid_spread_type(reduced) } - /// `getLiteralTypeFromPropertyName` of the name `key` of a class member or of a property of an - /// object literal or a binding pattern. `None`: the name is missing. + /// `getLiteralTypeFromPropertyName` of the name `key` at `pos` of a class member or of a + /// property of an object literal or a binding pattern. `None`: the name is missing. pub(super) fn literal_type_from_property_name( &mut self, file: FileId, key: PropKey, name_kind: NameKind, + pos: u32, ) -> Option { match key { PropKey::Private(_) => Some(TypeId::NEVER), @@ -2917,7 +3110,12 @@ impl<'p, 's> Checker<'p, 's> { let key = self.check_computed_property_name(file, e); Some(self.regular(key)) } - PropKey::None => None, + // A name that declares nothing (`getDeclarationName`) is not stored. + PropKey::None if is_private_name_at(self.hir(file), pos) => Some(TypeId::NEVER), + PropKey::None => { + let text = self.get_property_name_for_property_name_node(file, key, pos)?; + Some(self.string_literal(text, false)) + } } } @@ -2952,13 +3150,14 @@ impl<'p, 's> Checker<'p, 's> { /// those whose name is in `omitted_keys`, the types of the names that are omitted by type: the /// computed ones that are not the name of a single property, and the numeric ones (`never`: /// there are none). `symbol`: the name of the binding element that declares the symbol the type - /// gets. + /// gets. `assigned_symbol`: the symbol it gets in a destructuring assignment. pub fn rest_of_object( &mut self, ty: TypeId, omitted: &[Atom], omitted_keys: TypeId, symbol: Option<(FileId, PatId)>, + assigned_symbol: Option, ) -> TypeId { let ty = self.filter(ty, |_, m| !m.is_null() && !m.is_undefined()); if ty.is_never() { @@ -2966,7 +3165,7 @@ impl<'p, 's> Checker<'p, 's> { } if self.is_union(ty) { return self.map_type(ty, |c, m| { - c.rest_of_object(m, omitted, omitted_keys, symbol) + c.rest_of_object(m, omitted, omitted_keys, symbol, assigned_symbol) }); } // `getPropertiesOfType`: a type parameter has the properties of its constraint. @@ -3022,41 +3221,27 @@ impl<'p, 's> Checker<'p, 's> { }; let mut shape = Shape::new_in(self.arena); let options = SpreadSymbolOptions { + owner: apparent, owner_is_generic: self.has_type_variables(apparent), readonly: false, resolves: false, }; for i in kept { let prop = &members.shape().props[i]; - let (source, mapper, read_with) = self.get_spread_symbol(prop, members.mapper, options); - let anew = prop - .flags - .intersects(PropFlags::WRITE_ONLY | PropFlags::READONLY); - // A copy: a readonly property of the original is writable in it. - let copied = if anew { - PropFlags::OPTIONAL | PropFlags::STRING_NAME - } else { - // `getSpreadSymbol` returns the symbol itself. - PropFlags::OPTIONAL | PropFlags::STRING_NAME | PropFlags::METHOD - }; - shape.props.push(Prop { - name: prop.name, - flags: prop.flags & copied | read_with, - source, - mapper, - }); + let member = self.get_spread_symbol(prop, members.mapper, options); + shape.props.push(member); } for info in &members.shape().index { let value = self.instantiate(info.value, members.mapper); shape.index.push(IndexInfo { value, ..*info }); - // Read by `getApplicableIndexSymbol`: `symbol.Parent = t.symbol`. - shape.symbol_declared_at = - symbol.map(|(file, name)| (file, self.hir(file)[name].pos, ExprId::NONE)); } if let Some((file, name)) = symbol { + shape.symbol_declared_at = Some((file, self.hir(file)[name].pos, ExprId::NONE)); let scope = self.enclosing_scope_of_pat(file, name); shape.mapper = self.identity_mapper_with_adopted(file, scope); } + shape.symbol = assigned_symbol; + shape.is_object_rest_type = true; self.synth(shape) } @@ -3229,16 +3414,27 @@ impl<'p, 's> Checker<'p, 's> { /// depends on it. #[inline] pub(super) fn is_resolved_on_request(&self, file: FileId, p: ParamId) -> bool { - let (hir, bound) = (self.hir(file), self.bound(file)); + let (hir, func) = (self.hir(file), self.bound(file).param_fn[p.idx()]); matches!(hir[hir[p].pat].kind, PatKind::Object(_) | PatKind::Array(_)) && hir[p].ty.is_none() - && bound.param_fn[p.idx()] - .some() - .is_some_and(|func| !matches!(bound.fns[func.idx()].owner, FnOwner::Expr(_))) + && func.is_some() + && !self.is_function_expression_or_object_literal_method(file, func) + } + + /// `IsFunctionExpressionOrArrowFunction(func) || IsObjectLiteralMethod(func)`: what + /// `checkFunctionExpressionOrObjectLiteralMethod` checks, and `assignParameterType` types the + /// parameters of. `checkAccessorDeclaration` checks an accessor of an object literal. + #[inline] + fn is_function_expression_or_object_literal_method(&self, file: FileId, func: FnId) -> bool { + matches!(self.bound(file).fns[func.idx()].owner, FnOwner::Expr(_)) + && !matches!(self.hir(file)[func].kind, FnKind::Getter | FnKind::Setter) } /// `links.resolvedType != nil` for the symbol of `p`, which `is_resolved_on_request`. fn is_parameter_symbol_resolved(&self, file: FileId, p: ParamId) -> bool { + if self.parameter_symbol_taken_as_unresolved == Some((file, p)) { + return false; + } let resolved = (self.p.resolved_parameter_symbols).get(&self.task, &(file, p)); // `reportCircularityError` has assigned it as well. let known = (self.p.pat_types).get(&self.task, &(file, self.hir(file)[p].pat)); @@ -3327,7 +3523,8 @@ impl<'p, 's> Checker<'p, 's> { /// `sig_params_up_to` for `compareSignaturesRelated`, after `sig_params(sig)` could not be /// stored. `assignParameterType` has given the parameters of a function expression that have no - /// annotation their types, so `tryGetTypeAtPosition` pushes no resolution for those. + /// annotation their types, so `tryGetTypeAtPosition` pushes no resolution for those. It does + /// for one whose type `assignParameterType` is still computing. pub(super) fn sig_params_compared_up_to( &mut self, sig: SigId, @@ -3340,7 +3537,13 @@ impl<'p, 's> Checker<'p, 's> { let hir = self.hir(file); let is_expression = matches!(self.bound(file).fns[func.idx()].owner, FnOwner::Expr(_)); for p in hir[func].params.iter().take(count) { - if hir[p].ty.is_some() || !is_expression { + let name = hir[p].pat; + let is_being_assigned = self.assigned_parameters.iter().any(|&at| { + matches!(self.stack.get(at), + Some(&(Query::Pat(of, it) | Query::ParameterSymbol(of, it))) + if (of, it) == (file, name)) + }); + if hir[p].ty.is_some() || !is_expression || is_being_assigned { self.type_of_param(file, p); } } @@ -3424,7 +3627,8 @@ impl<'p, 's> Checker<'p, 's> { let index = (p.0 - hir[func].params.start) as usize; // The getter determines the type. if hir[func].kind == FnKind::Setter - && let Some((of, getter)) = self.sibling_accessor(file, func, FnKind::Getter) + && let Some((of, getter)) = + self.sibling_accessor_at_this_moment(file, func, FnKind::Getter) { let ty = self.return_type_of_fn(of, getter); return self.widened_for_declaration(ty, Some((file, param.pat))); @@ -3484,7 +3688,7 @@ impl<'p, 's> Checker<'p, 's> { // that of any parameter of a function expression. For a pattern in a declaration // `type_of_param_on_request` reports. let is_requested_for = matches!(hir[param.pat].kind, PatKind::Ident(_)) - || matches!(self.bound(file).fns[func.idx()].owner, FnOwner::Expr(_)); + || self.is_function_expression_or_object_literal_method(file, func); let ty = self.widened_for_declaration(ty, is_requested_for.then_some((file, param.pat))); // `addOptionalityEx` @@ -3496,9 +3700,10 @@ impl<'p, 's> Checker<'p, 's> { } // `getTypeFromBindingPattern`, for a rest parameter too: `any[]` is only for one with no // type information at all. - if let Some(implied) = self.type_from_binding_pattern_of_param(file, func, p) { + if let Some(implied) = self.type_from_binding_pattern_of_param(file, p) { // As for a pattern with a default. - let name = matches!(self.bound(file).fns[func.idx()].owner, FnOwner::Expr(_)) + let name = self + .is_function_expression_or_object_literal_method(file, func) .then_some((file, param.pat)); return self.widened_for_declaration(implied, name); } @@ -3537,13 +3742,9 @@ impl<'p, 's> Checker<'p, 's> { check_mode: CheckMode, ) -> TypeId { let param = &self.hir(file)[p]; - let for_rest = match check_mode.contains(CheckMode::REST_BINDING_ELEMENT) { - true => self.type_of_reference_for_rest(file, param.default), - false => None, - }; - let ty = match for_rest { - Some(ty) => ty, - None => self.type_of_declaration_initializer(file, param.default), + let ty = match check_mode.contains(CheckMode::REST_BINDING_ELEMENT) { + true => self.check_declaration_initializer_for_rest(file, param.default), + false => self.type_of_declaration_initializer(file, param.default), }; let ty = self.padded_for_pattern(file, param.pat, ty); let widened = self.get_widened_literal_type_for_initializer(file, param.pat, ty); @@ -3723,38 +3924,62 @@ impl<'p, 's> Checker<'p, 's> { } } - /// `GetDeclarationOfKind(getSymbolOfDeclaration(accessor), kind)`: the getter, or the setter if - /// that is `expected`, that shares one symbol with the accessor `func`, in a class, an interface, - /// a type literal or an object literal. + /// `GetDeclarationOfKind(symbol, kind)`: the getter, or the setter if that is `expected`, that + /// shares one symbol with the accessor `func`, in a class, an interface, a type literal or an + /// object literal, once the members of that are resolved. pub(super) fn sibling_accessor( &mut self, file: FileId, func: FnId, expected: FnKind, ) -> Option<(FileId, FnId)> { + let accessor = self.declaration_of_accessor(file, func)?; + let declarations = self.declarations_of_member(file, accessor); + self.get_accessor_of_kind(declarations, expected) + } + + /// `GetDeclarationOfKind(getSymbolOfDeclaration(accessor), kind)` at this moment, while `func` + /// is checked. + pub(super) fn sibling_accessor_at_this_moment( + &mut self, + file: FileId, + func: FnId, + expected: FnKind, + ) -> Option<(FileId, FnId)> { + let accessor = self.declaration_of_accessor(file, func)?; + let declarations = self.declarations_of_symbol_of_checked_declaration(file, accessor); + self.get_accessor_of_kind(declarations, expected) + } + + fn declaration_of_accessor(&self, file: FileId, func: FnId) -> Option { let bound = self.bound(file); - let accessor = match bound.fns[func.idx()].owner { - FnOwner::Member(m) => Decl::Member(m), + match bound.fns[func.idx()].owner { + FnOwner::Member(m) => Some(Decl::Member(m)), FnOwner::Expr(e) => match bound.expr_parent[e.idx()] { - Parent::Prop(p) => Decl::Property(p), - _ => return None, + Parent::Prop(p) => Some(Decl::Property(p)), + _ => None, }, - _ => return None, - }; - self.declarations_of_member(file, accessor) - .into_iter() - .find_map(|(of, declaration)| { - let hir = self.hir(of); - let other = match declaration { - Decl::Member(m) => hir[m].func, - Decl::Property(p) if hir[p].value.is_some() => match hir[hir[p].value].kind { - ExprKind::Fn(f) => f, - _ => FnId::NONE, - }, + _ => None, + } + } + + fn get_accessor_of_kind( + &self, + declarations: List<'p, (FileId, Decl)>, + expected: FnKind, + ) -> Option<(FileId, FnId)> { + declarations.into_iter().find_map(|(of, declaration)| { + let hir = self.hir(of); + let other = match declaration { + Decl::Member(m) => hir[m].func, + Decl::Property(p) if hir[p].value.is_some() => match hir[hir[p].value].kind { + ExprKind::Fn(f) => f, _ => FnId::NONE, - }; - (other.is_some() && hir[other].kind == expected).then_some((of, other)) - }) + }, + _ => FnId::NONE, + }; + (other.is_some() && hir[other].kind == expected).then_some((of, other)) + }) } // ───────────────────────────── return types of functions ───────────────────────────── @@ -3844,6 +4069,43 @@ impl<'p, 's> Checker<'p, 's> { ty } + /// Whether `checkExpression` of `node`, which has been checked, has another result or effect + /// than the first time: a reference in it got `errorType` from `getFlowTypeOfReference`, under + /// `flowAnalysisDisabled` or at the depth limit of `getTypeAtFlowNode`, and the flag is reset. + /// No type of a reference is stored, so its flow is walked again. `getResolvedSignature` stores + /// its result, and the check of a function or a class is deferred. + fn has_reference_without_flow_type(&mut self, file: FileId, node: Node) -> bool { + // A walk nests at most once per flow node. + if self.flow_analysis_disabled + || self.bound(file).flow_places <= super::flow::MAX_FLOW_DEPTH + { + return false; + } + let hir = self.hir(file); + let kind = hir.kind(node); + if kind.is_function_like() + || kind.is_class_like() + || matches!( + kind, + Kind::CallExpression | Kind::NewExpression | Kind::TaggedTemplateExpression + ) + { + return false; + } + if (kind.is_access_expression() || matches!(kind, Kind::Identifier | Kind::ThisKeyword)) + && matches!(hir.data(node), NodeData::Expr(e) + if self.cached_type_of_expr(file, e) == Some(TypeId::ERROR)) + { + return true; + } + let mut children: SmallVec<[Node; 8]> = SmallVec::new(); + hir.for_each_child(node, &mut |child| { + children.push(child); + false + }); + (children.into_iter()).any(|child| self.has_reference_without_flow_type(file, child)) + } + /// `getReturnTypeFromAnnotation`, then `getReturnTypeFromBody`. It pushes no resolution and caches nothing. pub(super) fn return_type_of_fn_uncached( &mut self, @@ -3858,7 +4120,7 @@ impl<'p, 's> Checker<'p, 's> { return ty; } match f.kind { - FnKind::Setter | FnKind::StaticBlock => return TypeId::VOID, + FnKind::StaticBlock => return TypeId::VOID, FnKind::Constructor | FnKind::ConstructSignature | FnKind::ConstructorType => { return TypeId::ANY; } @@ -3959,7 +4221,11 @@ impl<'p, 's> Checker<'p, 's> { let operand = if value.is_none() { self.undefined_widening() } else { - let ty = self.check_expression_cached_ex(file, value, check_mode); + // FOR SPEED: `checkExpressionEx` stores nothing. + let mut ty = self.check_expression_cached_ex(file, value, check_mode); + if self.has_reference_without_flow_type(file, hir.node(value)) { + ty = self.check_expression_afresh(file, value, check_mode); + } self.regular_in_const_context(file, value, ty) }; let yielded = @@ -4377,7 +4643,8 @@ impl<'p, 's> Checker<'p, 's> { return self.awaited_no_alias_uncached(ty, error); } // `c.cachedTypes[key]`, which holds no nil. A caller that finds a result reports nothing, - // not even what the first caller found in a member of a union. + // not even what the first caller found in a member of a union. The requests for the + // members of a union and for a promised type go through it like any other. let cached = self.p.awaited_types.get(&self.task, &ty); if let Some(awaited) = cached && (awaited.is_some() || error.is_none()) @@ -4388,6 +4655,9 @@ impl<'p, 's> Checker<'p, 's> { let awaited = self.awaited_no_alias_uncached(ty, error); if let Ok(stored) = self.end_scope_by_counters(scope) && cached.is_none() + // No result can be due to `awaitedTypeStack`. Without that it is kept, for a caller + // that does not report. + && (awaited.is_some() || self.awaiting.is_empty()) // A result that depends on one of these is not cacheable, and `non_cacheable_mark` does not always show it. && self.inference_contexts.is_empty() && self.provisional.is_empty() @@ -4407,8 +4677,7 @@ impl<'p, 's> Checker<'p, 's> { /// Returns whether there is none: in that case a result computed from a type now is valid at /// any time. fn is_no_type_resolution_in_progress(&self) -> bool { - self.awaiting.is_empty() - && self.instantiation_depth == 0 + self.instantiation_depth == 0 && self.never_in_progress.is_empty() && self.variances_in_progress.is_empty() && self.constraint_stack.is_empty() @@ -4676,6 +4945,13 @@ impl<'p, 's> Checker<'p, 's> { .unwrap_or(TypeId::ANY) } + /// `checkIteratedTypeOrElementType(IterationUseDestructuring, .., nil /*errorNode*/)` + pub(super) fn iterated_type_of_destructuring_in_flow(&mut self, ty: TypeId) -> TypeId { + let usage = IterationUse::DestructuringInFlow; + self.iterated_type_or_element_type(usage, ty, TypeId::UNDEFINED, None) + .unwrap_or(TypeId::ANY) + } + /// `iterated_type` pub(super) fn checked_iterated_type(&mut self, ty: TypeId, is_async: bool) -> TypeId { self.iterated_type(ty, is_async) @@ -4840,6 +5116,9 @@ impl<'p, 's> Checker<'p, 's> { return TypeId::ANY; }; let is_async = self.hir(file)[func].flags.contains(Flags::ASYNC); + if star && is_async { + self.note_external_emit_helpers_check(file, e); + } // "There is no point in doing an assignability check if the function has no explicit return type" let mut return_type = self.return_type_from_annotation(file, func); if let Some(declared) = return_type @@ -5021,7 +5300,7 @@ impl<'p, 's> Checker<'p, 's> { ) -> Iter3 { let ty = self.reduced(ty); if self.is_any(ty) { - return Iter3::all(ty); + return Iter3::any(ty); } let key = (ty, usage.cache_flags()); let cached = self.iteration_types_cache.get(&key).copied(); @@ -5039,17 +5318,27 @@ impl<'p, 's> Checker<'p, 's> { let (before, reported) = (self.non_cacheable_mark(), self.reported.len()); let types = self.iterable_types_worker(ty, usage, error_node); // `noCache` - if !matches!(cached, Some((_, true))) - && before == self.non_cacheable_mark() - // A frame that drops its diagnostics reports them when it is evaluated again. - && !(self.reported.len() > reported - && self.frames.last().is_some_and(|frame| frame.drops_reported)) - { + if !matches!(cached, Some((_, true))) && before == self.non_cacheable_mark() { self.iteration_types_cache.insert(key, (types, is_request)); + if self.reported.len() > reported && !self.frames.is_empty() { + self.reported_iteration_requests.push((self.work, key)); + } } types } + /// What the requests `reported_iteration_requests[from..]` have reported is kept for good or, + /// if `is_dropped`, reported by the next evaluation: their entries are a memo only. tsgo never + /// drops a diagnostic, so there the first request is the one that reports. + pub(super) fn settle_iteration_requests(&mut self, from: usize, is_dropped: bool) { + let from = from.min(self.reported_iteration_requests.len()); + for (_, key) in self.reported_iteration_requests.drain(from..) { + if is_dropped && let Some(entry) = self.iteration_types_cache.get_mut(&key) { + entry.1 = false; + } + } + } + /// `getIterationTypesOfIterableWorker` fn iterable_types_worker( &mut self, @@ -5137,28 +5426,31 @@ impl<'p, 's> Checker<'p, 's> { /// lib.es2015.iterable.d.ts declares the `[Symbol.iterator]` of `Array`, `ReadonlyArray` and /// `String`. `None`: `ty` is something else, or the members of its interface decide. fn yield_type_by_default_library(&mut self, ty: TypeId) -> Option { - let (interface, arity, element) = match self.data(ty) { - TypeData::Tuple { - flags, readonly, .. - } => { - let interface = if *readonly { - known::ReadonlyArray - } else { - known::Array - }; + if !self.is_iterable_by_default_library(ty) { + return None; + } + match self.data(ty) { + TypeData::Tuple { flags, .. } => { let elems = self.type_arguments(ty); - (interface, 1, self.tuple_element_union(elems, flags)) + Some(self.tuple_element_union(elems, flags)) } - TypeData::Ref { target, .. } => ( - self.files().symbol(*target).name, - 1, - self.array_element(ty)?, - ), - _ if self.is_string_like(ty) => (known::String, 0, TypeId::STRING), - _ => return None, + TypeData::Ref { .. } => self.array_element(ty), + _ => Some(TypeId::STRING), + } + } + + /// Whether `yield_type_by_default_library` has an answer for `ty`. + fn is_iterable_by_default_library(&self, ty: TypeId) -> bool { + let (interface, arity) = match self.data(ty) { + TypeData::Tuple { readonly: true, .. } => (known::ReadonlyArray, 1), + TypeData::Tuple { .. } => (known::Array, 1), + TypeData::Ref { target, .. } if self.is_array(ty) => { + (self.files().symbol(*target).name, 1) + } + _ if self.is_string_like(ty) => (known::String, 0), + _ => return false, }; self.has_iteration_methods_of_default_library(interface, arity) - .then_some(element) } /// Whether the default library alone declares the `[Symbol.iterator]` of the global interface @@ -5391,7 +5683,7 @@ impl<'p, 's> Checker<'p, 's> { return Iter3::default(); }; if self.is_any(method) { - return Iter3::all(method); + return Iter3::any(method); } // The intersection of the return types of its call signatures that accept zero arguments. let mut iterators = Vec::new(); @@ -5432,7 +5724,7 @@ impl<'p, 's> Checker<'p, 's> { mut diagnostic_output: Option<&mut Vec>, ) -> Iter3 { if self.is_any(ty) { - return Iter3::all(ty); + return Iter3::any(ty); } let names = if is_async { [ @@ -5498,7 +5790,7 @@ impl<'p, 's> Checker<'p, 's> { self.filter(declared, |c, m| !c.is_nullish(m)) }; if self.is_any(method) { - return Iter3::all(method); + return Iter3::any(method); } } let signatures = self.signatures(method, false); @@ -5621,7 +5913,7 @@ impl<'p, 's> Checker<'p, 's> { /// type of `next`. fn iteration_types_of_iterator_result(&mut self, ty: TypeId) -> Iter3 { if self.is_any(ty) { - return Iter3::all(ty); + return Iter3::any(ty); } if let Some(name) = self.atoms().lookup(b"IteratorYieldResult") && let Some(&[value]) = self.is_global_ref(ty, name, 1) diff --git a/src/sema/check/task_tests.rs b/src/sema/check/task_tests.rs index 679a0e51a8f4..695c44a1cec8 100644 --- a/src/sema/check/task_tests.rs +++ b/src/sema/check/task_tests.rs @@ -1290,6 +1290,8 @@ fn a_borrowed_key_finds_the_type_that_was_interned_with_its_lists() { is_enum: true, stored_under: None, is_array_literal: false, + is_array_pattern: false, + has_other_instantiation: false, }; let id = types.intern_key_with(TypeKey::Union(&members), &borrowed); let owned = Provenance { @@ -1298,6 +1300,8 @@ fn a_borrowed_key_finds_the_type_that_was_interned_with_its_lists() { is_enum: true, stored_under: None, is_array_literal: false, + is_array_pattern: false, + has_other_instantiation: false, }; assert_eq!(types.intern_with(TypeData::Union(list()), owned), id); assert_ne!(types.intern_key(TypeKey::Union(&members)), id); diff --git a/src/sema/check/unions.rs b/src/sema/check/unions.rs index 54445f3079a4..cdfb759e7524 100644 --- a/src/sema/check/unions.rs +++ b/src/sema/check/unions.rs @@ -9,6 +9,10 @@ type Place = (bool, FileId, u32); /// The members of a union or an intersection under construction. type Flat = smallvec::SmallVec<[TypeId; 16]>; +/// `getIntersectionKey`: the set, `IntersectionFlagsNoConstraintReduction`, and without that flag +/// the alias. +pub(super) type IntersectionKey = (Box<[TypeId]>, bool, Option<(Sym, Box<[TypeId]>)>); + /// `T & P` as `constrained_type_variable` takes it apart. #[derive(Copy, Clone)] struct ConstrainedTypeVariable { @@ -272,7 +276,6 @@ impl<'p, 's> Checker<'p, 's> { self.sort_type_set(types, &mut members); match members[..] { [] => TypeId::NEVER, - [only] => only, _ => self.union_of_named_unions(types, &members), } } @@ -439,7 +442,6 @@ impl<'p, 's> Checker<'p, 's> { let first_new_type_id = self.types().first_new_type_id(); let union = match members[..] { [] => TypeId::NEVER, - [only] => only, _ => self.union_of_named_unions(actual, &members), }; if includes_removed_pattern && self.types().is_new_since(union, first_new_type_id) { @@ -448,13 +450,17 @@ impl<'p, 's> Checker<'p, 's> { (union, is_plain) } - /// The end of `getUnionTypeWorker`: the union of `members`, in order, which was built from - /// `actual`. It has a denormalized `origin` if some of `actual` are named unions, or were built - /// from named unions, and no member belongs to two of them. + /// The end of `getUnionTypeWorker`: the union of `members`, in order and at least one, which was + /// built from `actual`. It has a denormalized `origin` if some of `actual` are named unions, or + /// were built from named unions, and no member belongs to two of them. A named union that has + /// all of them is the result, also if a reduction has left one member of it. fn union_of_named_unions(&self, actual: &[TypeId], members: &[TypeId]) -> TypeId { let mut named: smallvec::SmallVec<[TypeId; 4]> = smallvec::SmallVec::new(); self.add_named_unions(&mut named, actual); if named.is_empty() { + if let [only] = members { + return *only; + } // One of `actual` may already be the whole union. let whole = actual .iter() @@ -486,6 +492,10 @@ impl<'p, 's> Checker<'p, 's> { { return only; } + // `getUnionTypeFromSortedList` + if let [only] = members { + return *only; + } let origin = if in_named.len() + origin.len() == members.len() { for &union in &named { self.insert_type(&mut origin, union); @@ -502,6 +512,8 @@ impl<'p, 's> Checker<'p, 's> { is_enum: false, stored_under: None, is_array_literal: false, + is_array_pattern: false, + has_other_instantiation: false, }, ) } @@ -711,26 +723,27 @@ impl<'p, 's> Checker<'p, 's> { if let [only] = types { return *only; } - let mut union = self.union(types); + let union = self.union(types); let TypeData::Union(members) = self.data(union) else { return union; }; + let mut members: Vec = members.to_vec(); // `removeRedundantLiteralTypes`, reduceVoidUndefined: `void` includes `undefined`. - if members.contains(&TypeId::VOID) && members.iter().any(|m| m.is_undefined()) { - union = self.filter(union, |_, m| !m.is_undefined()); + if members.contains(&TypeId::VOID) { + members.retain(|m| !m.is_undefined()); } - let TypeData::Union(members) = self.data(union) else { - return union; - }; + let is_reduced = members.len() != self.parts(union).len(); // Primitives and literals were handled above. if !members .iter() .any(|&m| self.flags(m) & tf::STRUCTURED_OR_INSTANTIABLE != 0) { - return union; + return match is_reduced { + true => self.union_of_named_unions(types, &members), + false => union, + }; } let len = members.len(); - let mut members: Vec = members.to_vec(); let mut actual: Vec = Vec::with_capacity(len); for &ty in types { actual.extend_from_slice(self.parts(ty)); @@ -749,8 +762,8 @@ impl<'p, 's> Checker<'p, 's> { }; // `removeSubtypes` iterates over the members from last to first in `CompareTypes` order, // which therefore decides which of two mutual subtypes is removed. Where that order falls - // back to ids, which depend on the thread here, declared types come before types created by - // expressions, and the latter keep the given order. + // back to ids, declared types stay in the order of their ids, in which `members` has them, + // and come before types created by expressions, which keep the given order. let key = |c: &Self, m: TypeId| { let created_by_expression = match c.data(m) { // `{ ...t, a: 1 }` @@ -759,10 +772,8 @@ impl<'p, 's> Checker<'p, 's> { } _ => is_created_by_expression(c, m), }; - ( - created_by_expression, - actual.iter().position(|&g| g == m).unwrap_or(usize::MAX), - ) + let position = || actual.iter().position(|&g| g == m).unwrap_or(usize::MAX); + created_by_expression.then(position) }; let mut compare = |&x: &TypeId, &y: &TypeId| { self.compare_types_without_ids(x, y) @@ -853,7 +864,7 @@ impl<'p, 's> Checker<'p, 's> { } } } - if keep.iter().all(|&k| k) { + if !is_reduced && keep.iter().all(|&k| k) { return union; } let mut kept: Flat = members @@ -865,7 +876,6 @@ impl<'p, 's> Checker<'p, 's> { self.sort_type_set(types, &mut kept); match kept[..] { [] => TypeId::NEVER, - [only] => only, _ => self.union_of_named_unions(types, &kept), } } @@ -937,6 +947,8 @@ impl<'p, 's> Checker<'p, 's> { is_enum: false, stored_under: None, is_array_literal: false, + is_array_pattern: false, + has_other_instantiation: false, }, ); // `ObjectFlagsPrimitiveUnion` is forwarded. @@ -1073,7 +1085,6 @@ impl<'p, 's> Checker<'p, 's> { } Some(match kept[..] { [] => TypeId::NEVER, - [only] => only, _ => self.union_of_named_unions(mapped, &kept), }) } @@ -1114,13 +1125,13 @@ impl<'p, 's> Checker<'p, 's> { /// `A & B & ...` pub fn intersection(&mut self, types: &[TypeId]) -> TypeId { - self.intersection_ex(types, false) + self.intersection_ex(types, false, None) } /// The same, but `T & P` is not reduced using the constraint of `T`. /// `IntersectionFlagsNoConstraintReduction` pub(super) fn intersection_without_constraint_reduction(&mut self, types: &[TypeId]) -> TypeId { - self.intersection_ex(types, true) + self.intersection_ex(types, true, None) } /// `addTypesToIntersection`, `addTypeToIntersection`: order is preserved, because it matters @@ -1178,29 +1189,13 @@ impl<'p, 's> Checker<'p, 's> { includes } - /// `getIntersectionTypeEx` - fn intersection_ex(&mut self, types: &[TypeId], no_constraint_reduction: bool) -> TypeId { - self.intersection_worker(types, no_constraint_reduction).0 - } - /// `getIntersectionTypeEx`, with an alias. pub(super) fn intersection_with_alias( &mut self, types: &[TypeId], alias: Option<(Sym, &[TypeId])>, ) -> TypeId { - match (self.intersection_worker(types, false), alias) { - ((created, true), Some((alias, type_arguments))) => { - // `getIntersectionKey` - self.get_symbol_id(alias); - let aliased = self.with_alias(created, alias, type_arguments); - if let Some(flag) = self.types().is_constrained_type_variable(created) { - self.types().set_constrained_type_variable(aliased, flag); - } - aliased - } - ((created, _), _) => created, - } + self.intersection_ex(types, false, alias) } /// `getUnionTypeEx`, with an alias. @@ -1208,6 +1203,16 @@ impl<'p, 's> Checker<'p, 's> { &mut self, types: &[TypeId], alias: Option<(Sym, &[TypeId])>, + ) -> TypeId { + self.union_ex_with_alias(types, true, alias) + } + + /// `union_ex`, with an alias. + fn union_ex_with_alias( + &mut self, + types: &[TypeId], + merge_constrained: bool, + alias: Option<(Sym, &[TypeId])>, ) -> TypeId { if let [only] = types { return *only; @@ -1218,7 +1223,7 @@ impl<'p, 's> Checker<'p, 's> { { self.get_symbol_id(alias); } - let created = self.union(types); + let created = self.union_ex(types, merge_constrained); match alias { Some((alias, type_arguments)) if self.is_union(created) => { self.union_type_with_alias(created, alias, type_arguments) @@ -1227,25 +1232,24 @@ impl<'p, 's> Checker<'p, 's> { } } - /// `getIntersectionTypeEx`. The flag: the result was created here, so the given alias, if any, - /// is its alias. A result that is the one remaining member of `types` was not. - fn intersection_worker( + /// `getIntersectionTypeEx` + fn intersection_ex( &mut self, types: &[TypeId], no_constraint_reduction: bool, - ) -> (TypeId, bool) { + alias: Option<(Sym, &[TypeId])>, + ) -> TypeId { let mut set = Flat::with_capacity(types.len()); let includes = self.add_types_to_intersection(&mut set, 0, types); if includes & tf::NEVER != 0 { - let never = if set.contains(&TypeId::SILENT_NEVER) { + return if set.contains(&TypeId::SILENT_NEVER) { TypeId::SILENT_NEVER } else { TypeId::NEVER }; - return (never, false); } if includes & tf::INCLUDES_UNRESOLVED != 0 { - return (TypeId::UNRESOLVED, false); + return TypeId::UNRESOLVED; } let strict = self.p.files.options.strict_null_checks; // No value is both an object and null or undefined, or belongs to two disjoint domains. @@ -1262,35 +1266,33 @@ impl<'p, 's> Checker<'p, 's> { || is_in_another_too(tf::ES_SYMBOL_LIKE) || is_in_another_too(tf::VOID_LIKE) { - return (TypeId::NEVER, false); + return TypeId::NEVER; } if includes & (tf::TEMPLATE_LITERAL | tf::STRING_MAPPING) != 0 && includes & tf::STRING_LITERAL != 0 && !self.extract_redundant_template_literals(&mut set) { - return (TypeId::NEVER, false); + return TypeId::NEVER; } if includes & tf::ANY != 0 { - let any = if includes & tf::INCLUDES_WILDCARD != 0 { + return if includes & tf::INCLUDES_WILDCARD != 0 { TypeId::WILDCARD } else if includes & tf::INCLUDES_ERROR != 0 { TypeId::ERROR } else { TypeId::ANY }; - return (any, false); } // Without strictNullChecks null and undefined were not added to the set, and the // intersection reduces to them. if !strict && includes & tf::NULLABLE != 0 { - let left = if includes & tf::INCLUDES_EMPTY_OBJECT != 0 { + return if includes & tf::INCLUDES_EMPTY_OBJECT != 0 { TypeId::NEVER } else if includes & tf::UNDEFINED != 0 { TypeId::UNDEFINED } else { TypeId::NULL }; - return (left, false); } // `{}` is removed next to a type that cannot be null or undefined // (`TypeFlagsDefinitelyNonNullable`), which is not known of a union. `U & {}`, where `U` is @@ -1323,13 +1325,13 @@ impl<'p, 's> Checker<'p, 's> { set[at] = TypeId::MISSING; } match set.len() { - 0 => return (TypeId::UNKNOWN, false), + 0 => return TypeId::UNKNOWN, // `getUnionTypeEx(constituents, UnionReductionLiteral, alias, nil)`: a separate union. 1 if is_distributed_over && self.is_union(set[0]) => { let members = self.parts(set[0]); - return (self.union(members), true); + return self.union_with_alias(members, alias); } - 1 => return (set[0], false), + 1 => return set[0], _ => {} } // `T & P` is reduced using the constraint of `T`. @@ -1346,7 +1348,7 @@ impl<'p, 's> Checker<'p, 's> { } = found; // `T & string` with `T extends "a" | "b"` is `T`. if self.is_strict_subtype(constraint, primitive) { - return (variable, false); + return variable; } // `T & number` is never: no member of the constraint of `T` is a subtype of `P`, and // `P` is not a subtype of the constraint of `T`. @@ -1354,30 +1356,39 @@ impl<'p, 's> Checker<'p, 's> { if !(parts.len() > 1 && parts.iter().any(|&p| self.is_strict_subtype(p, primitive))) && !self.is_strict_subtype(primitive, constraint) { - return (TypeId::NEVER, false); + return TypeId::NEVER; } is_constrained_type_variable = true; } + let alias_in_key = alias.filter(|_| !no_constraint_reduction); + if let Some((alias, _)) = alias_in_key { + self.get_symbol_id(alias); + } if includes & tf::UNION == 0 { - let created = self.intern_key(TypeKey::Intersection(&set)); + let created = + self.intern_key_with_alias(TypeKey::Intersection(&set), alias, OriginKey::None); if !no_constraint_reduction && set.len() == 2 { self.types() .set_constrained_type_variable(created, is_constrained_type_variable); } - return (created, true); + return created; } - // `intersectionTypes`: the cached result for the same types. The number of `types` is not - // in the key: the first request decides whether the set is split in halves. - let key = (Box::<[TypeId]>::from(&set[..]), no_constraint_reduction); + // `intersectionTypes`: the cached result for the same types and alias. The number of + // `types` is not in the key: the first request decides whether the set is split in halves. + let key: IntersectionKey = ( + Box::from(&set[..]), + no_constraint_reduction, + alias_in_key.map(|(alias, type_arguments)| (alias, Box::from(type_arguments))), + ); let table = &self.p.distributed_intersections; if let Some(known) = table.get(&self.task, &key) { return known; } let scope = self.begin_scope(); - let result = self.distribute_intersection(types.len(), set, no_constraint_reduction); + let result = self.distribute_intersection(types.len(), set, no_constraint_reduction, alias); match (result, self.end_scope_by_counters(scope)) { // `return c.errorType`, before the result is stored: the next request reports again. - (None, _) => (TypeId::ERROR, false), + (None, _) => TypeId::ERROR, (Some(result), Ok(stored)) => table.insert(&self.task, key, result, stored), (Some(result), Err(_)) => result, } @@ -1410,10 +1421,11 @@ impl<'p, 's> Checker<'p, 's> { actual: usize, mut set: Flat, no_constraint_reduction: bool, - ) -> Option<(TypeId, bool)> { + alias: Option<(Sym, &[TypeId])>, + ) -> Option { if self.intersect_unions_of_primitive_types(&mut set) { // Happens only once: at most one such union is left. - return Some(self.intersection_worker(&set, no_constraint_reduction)); + return Some(self.intersection_ex(&set, no_constraint_reduction, alias)); } // `(A | undefined) & (B | undefined)` is `A & B | undefined`, and likewise for `null`. if set @@ -1428,9 +1440,9 @@ impl<'p, 's> Checker<'p, 's> { for t in &mut set { *t = self.filter(*t, |_, m| !m.is_undefined()); } - let rest = self.intersection_ex(&set, no_constraint_reduction); - let union = self.union_ex(&[rest, undefined], !no_constraint_reduction); - return Some((union, self.is_union(union))); + let rest = self.intersection_ex(&set, no_constraint_reduction, None); + let types = [rest, undefined]; + return Some(self.union_ex_with_alias(&types, !no_constraint_reduction, alias)); } if set .iter() @@ -1439,17 +1451,17 @@ impl<'p, 's> Checker<'p, 's> { for t in &mut set { *t = self.filter(*t, |_, m| !m.is_null()); } - let rest = self.intersection_ex(&set, no_constraint_reduction); - let union = self.union_ex(&[rest, TypeId::NULL], !no_constraint_reduction); - return Some((union, self.is_union(union))); + let rest = self.intersection_ex(&set, no_constraint_reduction, None); + let types = [rest, TypeId::NULL]; + return Some(self.union_ex_with_alias(&types, !no_constraint_reduction, alias)); } // `A & B & C & D` is `(A & B) & (C & D)`: much of a half may reduce to never. Not applied // to two types, which would recurse forever. if set.len() >= 3 && actual > 2 { let middle = set.len() / 2; - let left = self.intersection_ex(&set[..middle], no_constraint_reduction); - let right = self.intersection_ex(&set[middle..], no_constraint_reduction); - return Some(self.intersection_worker(&[left, right], no_constraint_reduction)); + let left = self.intersection_ex(&set[..middle], no_constraint_reduction, None); + let right = self.intersection_ex(&set[middle..], no_constraint_reduction, None); + return Some(self.intersection_ex(&[left, right], no_constraint_reduction, alias)); } // `X & (A | B) & (C | D)` is `X & A & C | X & A & D | X & B & C | X & B & D`. let size = self.checked_cross_product_union_size(&set)?; @@ -1464,21 +1476,24 @@ impl<'p, 's> Checker<'p, 's> { n /= alternatives.len(); } } - let one = self.intersection_ex(&constituents, no_constraint_reduction); + let one = self.intersection_ex(&constituents, no_constraint_reduction, None); if !one.is_never() { intersections.push(one); } } - let union = self.union_ex(&intersections, !no_constraint_reduction); // The denormalized `origin`: where a constituent is an intersection and the origin has fewer constituents than the union. - if self.is_union(union) - && intersections.iter().any(|&t| self.is_intersection(t)) + if !(intersections.iter().any(|&t| self.is_intersection(t)) && self.constituent_count_of_types(&intersections) - > self.constituent_count_of_types(&set) + > self.constituent_count_of_types(&set)) { - return Some((self.with_origin(union, OriginKey::Intersection(&set)), true)); + return Some(self.union_ex_with_alias(&intersections, !no_constraint_reduction, alias)); } - Some((union, self.is_union(union))) + let union = self.union_ex(&intersections, !no_constraint_reduction); + if !self.is_union(union) { + return Some(union); + } + let members = TypeKey::Data(self.data(union)); + Some(self.intern_key_with_alias(members, alias, OriginKey::Intersection(&set))) } /// `getConstituentCount` @@ -2005,9 +2020,10 @@ impl<'p, 's> Checker<'p, 's> { .. } => 2, TypeData::Synth(ref shape) => u8::from(shape.is_regular), - // `createArrayLiteralType` + // `createArrayLiteralType`, `getTypeFromArrayBindingPattern` TypeData::Ref { .. } | TypeData::Tuple { .. } => { u8::from(self.types().is_array_literal(t)) + + 2 * u8::from(self.types().is_array_pattern(t)) } _ => 0, }; @@ -2187,7 +2203,26 @@ impl<'p, 's> Checker<'p, 's> { }) } }; - by_structure.then_with(|| creation_step(a).cmp(&creation_step(b))) + // The calls of `checkObjectLiteral` for one literal, in the order in which they return. + let check_of_literal = |t: TypeId| match *self.data(t) { + TypeData::Anon { + origin: + Origin::ObjectLiteral(_, _, _, created_by, ..) + | Origin::WidenedLiteral(_, _, _, created_by, ..), + .. + } => match created_by { + // The call for a member contains those for the members after it. + ObjectLiteralCheck::ForThisParameter(member) => (0u8, !member.0), + ObjectLiteralCheck::ForParent | ObjectLiteralCheck::ForAssignmentDeclaration => { + (1, 0) + } + ObjectLiteralCheck::ForThis => (2, 0), + }, + _ => (1, 0), + }; + by_structure + .then_with(|| check_of_literal(a).cmp(&check_of_literal(b))) + .then_with(|| creation_step(a).cmp(&creation_step(b))) } /// `CompareTypes`: the order of the constituents of a union, and of an origin that is a union. Where tsgo falls back to the type ids, diff --git a/src/sema/config.rs b/src/sema/config.rs index 6809193fa52e..189c000429a1 100644 --- a/src/sema/config.rs +++ b/src/sema/config.rs @@ -7,8 +7,9 @@ use crate::json::{Json, TsConfigSourceFile}; use crate::resolve::{ Host, Options, ancestors, combine_paths, contains_path, displayed_path, equate_string_case_insensitive, extra_supported_extensions, file_extension_is_one_of, - get_base_file_name, get_relative_path_from_directory, inside, is_rooted_disk_path, - is_same_path, join, known_extension, remove_file_extension, supported_extensions, to_path, + get_base_file_name, get_path_components, get_relative_path_from_directory, inside, + is_rooted_disk_path, is_same_path, join, known_extension, remove_file_extension, + supported_extensions, to_lowercase_unicode_15, to_path, typescript_path, }; use crate::session::Session; use crate::verify::{Place, Problem}; @@ -624,23 +625,27 @@ fn validate_specs( .collect() } -/// The same, with `over` applied after everything in the configuration file: the options a command -/// line adds to it, which may depend on whether the file has `references`. The result owns its -/// memory: `session` only holds what is of no use afterwards. +/// `GetParsedCommandLineOfConfigFilePath`. `over` is applied after everything in the configuration +/// file: the options a command line adds to it, which may depend on whether the file has +/// `references`. `Err`: the file cannot be read, and there is no project. A file that the parser +/// gives up on is an empty one, with the error. The result owns its memory: `session` only holds +/// what is of no use afterwards. pub fn load_overriding( host: &dyn Host, session: &Session, path: &[u8], over: &dyn Fn(bool) -> Vec<(Vec, Json)>, -) -> Project { +) -> Result> { let mut errors = Vec::new(); let raw = parse_config(host, session, path, &mut Vec::new(), &mut errors); - let mut raw = raw.unwrap_or_default(); + let Some(mut raw) = raw.or_else(|| host.read(path).map(|_| Raw::default())) else { + return Err(errors); + }; let base = dirname::(path); let references = get_project_references(&raw.references, base); let has_references = references.is_some_and(|list| !list.is_empty()); merge_compiler_options(&mut raw.compiler, over(has_references), &[]); - project_from_raw(host, session, path, base, raw, errors) + Ok(project_from_raw(host, session, path, base, raw, errors)) } /// The project consisting of `files` only, or of everything under `dir` if `files` is empty, with @@ -817,7 +822,7 @@ fn project_from_raw( } /// `ChangeExtension` -fn change_extension(path: &[u8], extension: &[u8]) -> Vec { +pub(crate) fn change_extension(path: &[u8], extension: &[u8]) -> Vec { match known_extension(path) { b"" => path.to_vec(), _ => [remove_file_extension(path), extension].concat(), @@ -847,7 +852,7 @@ pub fn matched_include_spec<'s>( .iter() .find(|spec| { GlobPattern::compile(&spec.1, base, Usage::Files, case_sensitive) - .is_some_and(|pattern| pattern.matches(path, b"")) + .is_some_and(|pattern| pattern.matches(typescript_path(path), b"")) }) .map(|spec| spec.0.as_slice()) .filter(|spec| !spec.is_empty()) @@ -905,7 +910,10 @@ fn file_names_from_specs( }) .collect() }); - if patterns.iter().any(|p| p.matches(&file, b"")) { + if patterns + .iter() + .any(|p| p.matches(typescript_path(&file), b"")) + { let key = key(&file); if !literal_files.contains_key(&key) && !wildcard_json_files.contains_key(&key) { @@ -1001,8 +1009,8 @@ fn is_package_folder(name: &[u8]) -> bool { || name.eq_ignore_ascii_case(b"bower_components") } -/// The path components of `prefix` followed by `suffix`, which is a single component or empty. The -/// root comes first, as `""`. +/// `nextPathPartParts`: the path components of `prefix` followed by `suffix`, which is a single +/// component or empty. `prefix` is a `typescript_path`. A `/` at its start comes first, as `""`. fn path_parts<'a>(prefix: &'a [u8], suffix: &'a [u8]) -> impl Iterator + Clone { let root = prefix.starts_with(b"/").then_some(&b""[..]); root.into_iter() @@ -1019,15 +1027,16 @@ impl GlobPattern { case_sensitive: bool, ) -> Option { let absolute = join(base, spec); - let mut parts: Vec<&[u8]> = std::iter::once(&b""[..]) - .chain(strings::split(&absolute, b"/").filter(|p| !p.is_empty())) - .collect(); + let mut parts = get_path_components(typescript_path(&absolute)); if usage != Usage::Exclude && parts.last() == Some(&&b"**"[..]) { return None; } + // No path part has a `/` in it, so nothing matches below `//server` or `http://host`. + let root = parts[0]; + parts[0] = root.strip_suffix(b"/").unwrap_or(root); if is_implicit_glob(parts.last().copied().unwrap_or(b"")) { - parts.push(b"**"); - parts.push(b"*"); + parts.push(&b"**"[..]); + parts.push(&b"*"[..]); } Some(GlobPattern { components: parts @@ -1189,11 +1198,11 @@ impl GlobPattern { /// `unicode.ToLower`: not the two characters that `char::to_lowercase` makes of U+0130. fn to_lower(c: char) -> char { - c.to_lowercase().next().unwrap_or(c) + to_lowercase_unicode_15(c).next().unwrap_or(c) } /// `strings.ToLower` -fn strings_to_lower(text: &[u8]) -> Vec { +pub(crate) fn strings_to_lower(text: &[u8]) -> Vec { let mut lower = Vec::with_capacity(text.len()); for c in text.chars().map(to_lower) { lower.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()); @@ -1361,18 +1370,19 @@ fn match_files( } else { [path, b"/"].concat() }; + let absolute = typescript_path(&prefix); Listed { files: files .into_iter() .filter(|file| file_extension_is_one_of(file, self.extensions)) .filter_map(|file| { - let index = self.files.matches_file(&prefix, &file)?; + let index = self.files.matches_file(absolute, &file)?; Some((index, [&prefix[..], &file[..]].concat())) }) .collect(), directories: directories .into_iter() - .filter(|directory| self.directories.matches_directory(&prefix, directory)) + .filter(|directory| self.directories.matches_directory(absolute, directory)) .map(|directory| [&prefix[..], &directory[..]].concat()) .collect(), } diff --git a/src/sema/config_options.rs b/src/sema/config_options.rs index f98a0946e569..2aa21edda8f7 100644 --- a/src/sema/config_options.rs +++ b/src/sema/config_options.rs @@ -184,7 +184,8 @@ pub struct Problem { /// Parses `--name text` from a command line: the canonical spelling of the option, which `name` /// matches case-insensitively, and its value. `None`: there is no such option, its value cannot be -/// expressed as a single word, or `text` is not a valid value for it. +/// expressed as a single word, or `text` is not a valid value for it. What is no key of the +/// `EnumMap` of the option is left as it is written, for `invalid_enum_type`. pub fn from_text(name: &[u8], text: &[u8]) -> Option<(&'static [u8], Json)> { let &(name, kind) = OPTIONS.get_ascii_case_insensitive(name)?; let value = match kind { @@ -193,7 +194,11 @@ pub fn from_text(name: &[u8], text: &[u8]) -> Option<(&'static [u8], Json)> { Kind::Boolean | Kind::Object | Kind::List(Element::Object) | Kind::ListOrElement => { return None; } - Kind::String | Kind::FilePath | Kind::OneOf(..) => Json::String(text.to_vec()), + Kind::String | Kind::FilePath => Json::String(text.to_vec()), + Kind::OneOf(..) => Json::String( + convert_json_option_of_enum_type(kind, text.trim_ascii()) + .unwrap_or_else(|| text.to_vec()), + ), Kind::Number => Json::Number(std::str::from_utf8(text.trim_ascii()).ok()?.parse().ok()?), // `ParseListTypeOption`: a flag is no list. Only the items of an enum-valued list are // trimmed. @@ -212,7 +217,10 @@ pub fn from_text(name: &[u8], text: &[u8]) -> Option<(&'static [u8], Json)> { } }) .filter(|item| !item.is_empty()) - .map(|item| Json::String(item.to_vec())) + .map(|item| { + let key = convert_json_option_of_enum_type(kind, item); + Json::String(key.unwrap_or_else(|| item.to_vec())) + }) .collect(), ), }; @@ -228,18 +236,33 @@ pub fn choices(name: &[u8]) -> Option<&'static [&'static [u8]]> { } } -/// The items of `value`, which `from_text` has made of the option `name`, that are not among the -/// allowed ones, if the option is a list of those: all that are allowed. -pub fn choices_of_list(name: &[u8], value: &Json) -> Option> { - let Kind::List(Element::Lib) = OPTIONS.get_ascii_case_insensitive(name)?.1 else { - return None; +/// `createDiagnosticForInvalidEnumType` for `value`, which `from_text` has made of the option +/// `name`: the allowed values, if it is no key of `EnumMap` or has an item that is none. +pub fn invalid_enum_type(name: &[u8], value: &Json) -> Option> { + let kind = OPTIONS.get_ascii_case_insensitive(name)?.1; + let is_key = |item: &Json| { + (item.as_str()).is_some_and(|it| convert_json_option_of_enum_type(kind, it).is_some()) }; - let is_allowed = |item: &Json| item.as_str().is_some_and(is_lib); - (!value.as_array()?.iter().all(is_allowed)).then(|| crate::resolve::LIBS.iter().collect()) + match kind { + Kind::OneOf(now, _) => (!is_key(value)).then(|| now.to_vec()), + Kind::List(Element::Lib) => { + let has_only_keys = value.as_array()?.iter().all(is_key); + (!has_only_keys).then(|| crate::resolve::LIBS.iter().collect()) + } + _ => None, + } } -fn is_lib(name: &[u8]) -> bool { - crate::resolve::LIBS.contains(&name.to_ascii_lowercase()) +/// `convertJsonOptionOfEnumType`: the key of `EnumMap` that `value` is, in whatever letter case. +/// `kind` is that of the option, or that of the list that has the option for its `Elements`. +fn convert_json_option_of_enum_type(kind: Kind, value: &[u8]) -> Option> { + let key = crate::config::strings_to_lower(value); + let is_key = match kind { + Kind::OneOf(now, once) => now.iter().chain(once).any(|&one| one == key), + Kind::List(Element::Lib) => crate::resolve::LIBS.contains(&key), + _ => false, + }; + is_key.then_some(key) } /// The rest of `convertJsonOption`, for a value of the right type. `convertJsonOptionOfListType` @@ -257,21 +280,30 @@ pub fn converted( Json::String(text) => text.is_empty() && name != b"moduleSuffixes", _ => false, }; - let normalized = |is_file_path: bool, value: &Json| match value { - Json::String(path) if is_file_path => Json::String( - crate::config::normalize_non_list_option_value(path, base_path), - ), - _ => value.clone(), - }; - match (kind_of(name), value) { - (Some(Kind::List(element)), Json::Array(items)) => Json::Array( + let kind = kind_of(name); + match (kind, value) { + (Some(Kind::List(_)), Json::Array(items)) => Json::Array( (items.iter().enumerate()) .filter(|(index, _)| !is_invalid(*index)) - .map(|(_, item)| normalized(element == Element::FilePath, item)) + .map(|(_, item)| converted_non_list(kind, item, base_path)) .filter(|item| !is_falsy(item)) .collect(), ), - (kind, _) => normalized(kind == Some(Kind::FilePath), value), + _ => converted_non_list(kind, value, base_path), + } +} + +/// `converted` for a value that is no list. `kind` is that of the option, or that of the list that +/// has the option for its `Elements`. +fn converted_non_list(kind: Option, value: &Json, base_path: &[u8]) -> Json { + match (kind, value) { + (Some(Kind::FilePath | Kind::List(Element::FilePath)), Json::String(path)) => Json::String( + crate::config::normalize_non_list_option_value(path, base_path), + ), + (Some(kind @ (Kind::OneOf(..) | Kind::List(Element::Lib))), Json::String(text)) => { + convert_json_option_of_enum_type(kind, text).map_or_else(|| value.clone(), Json::String) + } + _ => value.clone(), } } @@ -510,7 +542,10 @@ pub fn problems(file: &TsConfigSourceFile, written: ExprId, within: In) -> Vec

continue, - (Element::Lib, Json::String(lib)) if lib.is_empty() || is_lib(lib) => { + (Element::Lib, Json::String(lib)) + if lib.is_empty() + || convert_json_option_of_enum_type(kind, lib).is_some() => + { continue; } (Element::Lib, Json::String(_)) => { @@ -535,12 +570,11 @@ pub fn problems(file: &TsConfigSourceFile, written: ExprId, within: In) -> Vec

match value.as_str() { + Kind::OneOf(now, _) => match value.as_str() { None => wrong(b"enum"), Some(b"") => {} Some(specified) => { - let specified = specified.to_ascii_lowercase(); - if !now.iter().chain(once).any(|&one| one == specified) { + if convert_json_option_of_enum_type(kind, specified).is_none() { out.push(Problem { property, index: None, diff --git a/src/sema/driver/host.rs b/src/sema/driver/host.rs index 278b090594ec..ec2dc7501205 100644 --- a/src/sema/driver/host.rs +++ b/src/sema/driver/host.rs @@ -982,13 +982,14 @@ fn unmarshal_fields(object: &ObjectJSON, has_duplicates: bool) -> Option { expected[at].1.unmarshal_json(data, is_map, has_duplicates); } for (name, field) in expected { - let shown = if field.valid { - field.value - } else { - field.actual + let (shown, value) = match field.valid { + true => (field.value, None), + false if matches!(field.actual, Some(Json::Object(_))) => (field.actual, None), + false => (field.actual, field.value), }; let null = (field.null && shown != Some(Json::Null)).then_some(Json::Null); - fields.extend(shown.into_iter().chain(null).map(|it| (name.to_vec(), it))); + let values = shown.into_iter().chain(null).chain(value); + fields.extend(values.map(|it| (name.to_vec(), it))); } Some(Json::Object(fields)) } diff --git a/src/sema/driver/lib.rs b/src/sema/driver/lib.rs index f79740591668..cf0f852af5ab 100644 --- a/src/sema/driver/lib.rs +++ b/src/sema/driver/lib.rs @@ -395,7 +395,7 @@ fn compiler_option_from_flag( name: &[u8], value: Option<&[u8]>, ) -> Result { - use bun_sema::config_options::{choices, choices_of_list, from_text, possible_option}; + use bun_sema::config_options::{choices, from_text, invalid_enum_type, possible_option}; // What `tsc` does instead of compiling. A configuration file may have them, to no effect. if [&b"all"[..], b"init", b"version"] .iter() @@ -418,16 +418,8 @@ fn compiler_option_from_flag( } None => return Err(FlagError::Unknown), }; - if let Some(allowed) = allowed - && !allowed.iter().any(|a| a.eq_ignore_ascii_case(value)) - { - return Err(FlagError::BadValue(match is_boolean { - true => Vec::new(), - false => allowed.to_vec(), - })); - } match from_text(name, value) { - Some((name, value)) => match choices_of_list(name, &value) { + Some((name, value)) => match invalid_enum_type(name, &value) { Some(allowed) => Err(FlagError::BadValue(allowed)), None => Ok(CompilerOption(name.to_vec(), value)), }, @@ -1190,7 +1182,7 @@ fn dependencies_not_installed( /// some, and each is loaded once. #[derive(Default)] struct Projects { - loaded: FxHashMap, config::Project>, + loaded: FxHashMap, Result>>, /// `Project::files`, to look a file up in. files: FxHashMap, FxHashSet>>, /// An entry point is JavaScript (`Request::are_entry_points`). It is of the project that would @@ -1199,13 +1191,38 @@ struct Projects { } impl Projects { - fn load(&mut self, disk: &host::Disk, request: &Request, config: &[u8]) -> &config::Project { + /// `None`: `config` cannot be read. + fn load( + &mut self, + disk: &host::Disk, + request: &Request, + config: &[u8], + ) -> Option<&config::Project> { + let loaded = (self.loaded.entry(config.to_vec())) + .or_insert_with(|| Self::load_from_disk(disk, request, config)); + loaded.as_ref().ok() + } + + /// `load`, and the project is handed over. + fn take( + &mut self, + disk: &host::Disk, + request: &Request, + config: &[u8], + ) -> Result> { + let loaded = self.loaded.remove(config); + loaded.unwrap_or_else(|| Self::load_from_disk(disk, request, config)) + } + + fn load_from_disk( + disk: &host::Disk, + request: &Request, + config: &[u8], + ) -> Result> { // `bun check` never emits: it is `tsc --noEmit`, which reports no error about an output path. // `tsc -b` has no such option. - self.loaded.entry(config.to_vec()).or_insert_with(|| { - config::load_overriding(disk, &Session::new(), config, &|_| { - overriding_options(request, false) - }) + config::load_overriding(disk, &Session::new(), config, &|_| { + overriding_options(request, false) }) } @@ -1227,7 +1244,7 @@ impl Projects { seen.push(config.to_vec()); let is_new = !self.files.contains_key(config); let counts_javascript = self.counts_javascript; - let project = self.load(disk, request, config); + let project = self.load(disk, request, config)?; let references: Vec> = (project.references.iter()) .map(|it| config::resolve_config_file_name_of_project_reference(&it.path)) .collect(); @@ -1240,7 +1257,9 @@ impl Projects { options.push((b"allowJs".to_vec(), Json::Bool(true))); options }; - config::load_overriding(disk, &Session::new(), config, &with_javascript).files + config::load_overriding(disk, &Session::new(), config, &with_javascript) + .map(|it| it.files) + .unwrap_or_default() } }; let paths = files.iter().map(|it| to_path(it, is_case_sensitive)); @@ -1268,7 +1287,9 @@ impl Projects { return; } seen.push(config.to_vec()); - let project = self.load(disk, request, config); + let Some(project) = self.load(disk, request, config) else { + return; + }; files.extend(project.files.iter().cloned()); let references: Vec> = (project.references.iter()) .map(|it| config::resolve_config_file_name_of_project_reference(&it.path)) @@ -1298,7 +1319,8 @@ impl Projects { return Ok(Some(owner)); } let project = self.load(disk, request, &nearest); - let is_solution = project.files.is_empty() && !project.references.is_empty(); + let is_solution = + project.is_some_and(|it| it.files.is_empty() && !it.references.is_empty()); Err((!is_solution).then_some(nearest)) } } @@ -1560,8 +1582,10 @@ fn check_paths(disk: &host::Disk, request: &Request) -> Report { let top = (config.as_deref().map(dirname::)) .filter(is_below) .unwrap_or(path); - let files = match &config { - Some(config) => projects.load(disk, request, config).files_under(disk, top), + // One that cannot be read excludes nothing. `check_project_of` reports it. + let project = (config.as_ref()).and_then(|it| projects.load(disk, request, it)); + let files = match project { + Some(project) => project.files_under(disk, top), None => project_without_config(disk, request, &cwd, &[]).files_under(disk, top), }; let (mut included, mut others) = (Vec::new(), Vec::new()); @@ -1664,14 +1688,26 @@ fn check_project_of( request: &Request, projects: &mut Projects, of: OfProject<'_>, - report: Report, + mut report: Report, started: Instant, ) -> Report { let mut project = match of.config { - Some(config) => { - projects.load(disk, request, config); - projects.loaded.remove(config).expect("loaded above") - } + Some(config) => match projects.take(disk, request, config) { + Ok(project) => project, + // `tscCompilation`: "these are unrecoverable errors--exit to report them as + // diagnostics". To a build, `upToDateStatusTypeConfigFileNotFound`. + Err(errors) => { + let errors = errors.iter().map(|it| of_config_error(disk, config, it)); + match request.build { + true => report + .diagnostics + .push(global(6053, &[displayed_path(config)])), + false => report.diagnostics.extend(errors), + } + report.load_time = started.elapsed(); + return report; + } + }, None => { let cwd = host::from_native(request.cwd); let files = of.named.map(|it| it.1).unwrap_or_default(); @@ -1789,10 +1825,11 @@ impl Graph<'_> { if self.tasks.contains_key(&path) { continue; } - let resolved = self.host.is_file(&config).then(|| { - let over = |_: bool| self.overrides.clone(); - config::load_overriding(self.host, self.session, &config, &over) - }); + let over = |_: bool| self.overrides.clone(); + let resolved = match self.host.is_file(&config) { + true => config::load_overriding(self.host, self.session, &config, &over).ok(), + false => None, + }; if let Some(project) = &resolved { queued.extend(referenced(project)); } @@ -2635,12 +2672,17 @@ fn check_named_files( if let Some(loaded) = request.loaded { loaded(program); } - if is_true(b"explainFiles") { + let explains_files = is_true(b"explainFiles"); + let explain_files = |has_made_diagnostics: bool| { let cwd = host::from_native(request.cwd); - report.listed_files = program.files.explain_files(host, &|file_name: &[u8]| { + let to_relative_file_name = |file_name: &[u8]| { get_relative_path_from_directory(&cwd, file_name, COMPARE_PATHS_CASE_SENSITIVE) - }); - } else if is_true(b"listFiles") || is_true(b"listFilesOnly") { + }; + program + .files + .explain_files(host, has_made_diagnostics, &to_relative_file_name) + }; + if !explains_files && (is_true(b"listFiles") || is_true(b"listFilesOnly")) { let file_name = |&file: &FileId| program.files.module(file).file_name(); let file_names = program.files.order.iter().map(file_name); report.listed_files = file_names @@ -2665,8 +2707,10 @@ fn check_named_files( match module.hir.kind { // Only parse errors are reported for JSON files. FileKind::Json => module.hir.has_parse_diagnostics, - _ if module.is_lib => !skip_lib_check && !skip_default_lib_check, - FileKind::Declaration => !skip_lib_check, + // `SkipTypeChecking`, and nothing is emitted for a declaration file. + FileKind::Declaration => { + !skip_lib_check && !(skip_default_lib_check && module.is_lib) + } FileKind::Ts | FileKind::Tsx => true, } }) @@ -3254,12 +3298,22 @@ fn check_named_files( finish_files(); let syntactic = std::mem::take(&mut *found.lock()); if !syntactic.is_empty() { + // `GetProgramDiagnostics` is not called. An incremental program asks for them when + // `Emit` writes its build info (`ensureHasErrorsForState`). + if explains_files { + let is_incremental = options.is_incremental || options.is_build; + report.listed_files = explain_files(is_incremental && !lists_files_only); + } report.diagnostics.extend(syntactic); report.files_not_checked = std::mem::take(&mut report.files_checked); report.diagnostics.extend(emit_on_early_exit()); break 'stages; } } + // Before a file is checked, which can free its HIR. + if explains_files { + report.listed_files = explain_files(true); + } report.diagnostics.append(&mut about_options); // `ListFilesOnly`: no checker is asked for anything, and `Emit` is not called. if lists_files_only { diff --git a/src/sema/hir.rs b/src/sema/hir.rs index 0261accb6458..d597374e4bb5 100644 --- a/src/sema/hir.rs +++ b/src/sema/hir.rs @@ -1145,6 +1145,8 @@ pub enum MemberKind { #[derive(Copy, Clone, Debug)] pub struct Member { pub kind: MemberKind, + /// The name `declareSymbolEx` gives its symbol: that of `node.Name()`, but `default` for a + /// member with that modifier (`default class: 1`). pub key: PropKey, pub flags: Flags, pub ty: TypeNodeId, @@ -1328,6 +1330,8 @@ pub struct Import { /// Position of the `*` of `* as namespace`. pub namespace_start: u32, pub named: Span, + /// `importClause.NamedBindings` is a `NamedImports`: `named` can be empty. + pub has_named_imports: bool, pub type_only: bool, /// `importClause.PhaseModifier` is `defer`. pub is_deferred: bool, @@ -1597,8 +1601,11 @@ pub enum TypeNodeKind { /// Syntax the type parser failed on. Error, /// An element of a heritage clause of an interface, or of an `implements` clause of a class, - /// whose expression is not an entity name, which is an error: `extends f()`. - Heritage(ExprId), + /// whose expression is not an entity name, which is an error: `extends f()`. + Heritage { + expr: ExprId, + args: IdList, + }, Keyword(Keyword), /// `A.B.C` Ref { @@ -1847,6 +1854,9 @@ pub struct FileIn { /// The spans of the JSDoc comments of a JavaScript file. Sorted. A node whose position is /// inside one is synthesized from a tag. pub jsdoc_comments: S::Few<(u32, u32)>, + /// `TokenFlagsPrecedingJSDocLeadingAsterisks`: the `*` at the start of a line of a type in a + /// JSDoc comment, which the scanner passed over as trivia of the next token. Sorted. + pub jsdoc_asterisks: S::Few, /// The nodes that have JSDoc comments, in a JavaScript file in which one has a `@satisfies` /// tag. Sorted by `token`. pub jsdoc_hosts: S::Few, @@ -1864,6 +1874,9 @@ pub struct FileIn { /// `checkUnmatchedJSDocParameters` calls `containsArgumentsReference`. Those of /// `jsdoc_param_errors` are among them, in the same order. pub functions_with_param_tags: S::Few, + /// `checkGrammarClassDeclarationHeritageClauses`: the classes with an `@augments` tag that does + /// not name the class of the `extends` clause, and the start of the 8023 in `diagnostics`. + pub unmatched_augments_tags: S::Few<(ClassId, u32)>, pub ids: S::List, pub numbers: S::List, @@ -2323,12 +2336,14 @@ impl FileBuilder { jsx_expressions: copy_to_arena(&mut self.jsx_expressions, arena), jsx_pragmas: self.jsx_pragmas, jsdoc_comments: few_to_arena(self.jsdoc_comments, arena), + jsdoc_asterisks: few_to_arena(self.jsdoc_asterisks, arena), jsdoc_hosts: few_to_arena(self.jsdoc_hosts, arena), jsdoc_types: few_to_arena(self.jsdoc_types, arena), jsdoc_modifiers: few_to_arena(self.jsdoc_modifiers, arena), jsdoc_member_comments: Cow::Owned(self.jsdoc_member_comments), jsdoc_param_errors: Cow::Owned(self.jsdoc_param_errors), functions_with_param_tags: few_to_arena(self.functions_with_param_tags, arena), + unmatched_augments_tags: few_to_arena(self.unmatched_augments_tags, arena), ids: copy_to_arena(&mut self.ids, arena), numbers: copy_to_arena(&mut self.numbers, arena), exprs: copy_to_arena(&mut self.exprs, arena), @@ -2501,8 +2516,16 @@ pub fn is_string_literal_like(hir: &File, e: ExprId) -> bool { /// `IsStringOrNumericLiteralLike` pub fn is_string_or_numeric_literal_like(hir: &File, e: ExprId) -> bool { - is_string_literal_like(hir, e) - || matches!(hir[e].kind, ExprKind::Number(_)) && !is_parenthesized(hir, e) + !is_parenthesized(hir, e) && is_string_or_numeric_literal_like_in_parentheses(hir, e) +} + +/// `IsStringOrNumericLiteralLike(SkipParentheses(e))` +pub fn is_string_or_numeric_literal_like_in_parentheses(hir: &File, e: ExprId) -> bool { + match hir[e].kind { + ExprKind::String(_) | ExprKind::Number(_) => true, + ExprKind::Template { exprs, .. } => exprs.is_empty(), + _ => false, + } } /// `IsSignedNumericLiteral` diff --git a/src/sema/json.rs b/src/sema/json.rs index c935391f9282..dd00ee1b0136 100644 --- a/src/sema/json.rs +++ b/src/sema/json.rs @@ -2,7 +2,7 @@ //! parsed by the one shared parser. use crate::atom::Interner; -use crate::check::spans::Spans; +use crate::check::spans::{Spans, skip_trivia}; use crate::config_options::Declaration; use crate::hir::{ Diagnostic, DiagnosticKind, ExprId, ExprKind, File, PropId, PropKind, StmtKind, UnOp, @@ -170,7 +170,9 @@ pub fn validate_json(hir: &mut File, text: &[u8]) { continue; } if !is_double_quoted(prop.pos) { - refused.push((prop.pos, 1327, spans.prop_name(p) as u32)); + // `getErrorSpanForNode`: a missing name is before the trivia. + let start = skip_trivia(spans.text, prop.pos as usize) as u32; + refused.push((start, 1327, spans.prop_name(p) as u32)); } prop.value } @@ -203,6 +205,11 @@ pub fn validate_json(hir: &mut File, text: &[u8]) { hir.diagnostics .to_mut() .extend(refused.iter().map(|&(start, code, end)| { + // Only a missing node ends where the text starts. + let end = match end { + 0 => Diagnostic::NO_LENGTH, + end => end, + }; Diagnostic::new(DiagnosticKind::Parse, (start, end), code, &[]) })); } diff --git a/src/sema/node.rs b/src/sema/node.rs index dd4f36de1188..2ab3cfe09dd3 100644 --- a/src/sema/node.rs +++ b/src/sema/node.rs @@ -1014,7 +1014,7 @@ impl bool + ?Sized> Children<'_, '_, V> { TypeNodeKind::Template { types, .. } => { self.one(node.with(Part::Head)) || self.wrapped(types, Part::Span) } - TypeNodeKind::Heritage(e) => self.one(e), + TypeNodeKind::Heritage { expr, args } => self.one(expr) || self.list(args), TypeNodeKind::Import { name, args, .. } => { self.one(file.attributes_of_import_type(t).unwrap_or(ExprId::NONE)) || self.one(name) @@ -1153,7 +1153,7 @@ impl bool + ?Sized> Children<'_, '_, V> { Part::ImportClause => match statement { Some(StmtKind::Import(i)) => { let has_bindings = file[i].namespace.is_some() - || !file[i].named.is_empty() + || file[i].has_named_imports || file[i].default.is_none(); self.part(row, Part::Name, file[i].default.is_some()) || self.part(row, Part::NamedBindings, has_bindings) @@ -1486,13 +1486,13 @@ impl<'s> File<'s> { } /// `operand`, which starts before its operand, parentheses included; not `operand as T`. - fn is_type_assertion(&self, e: ExprId, operand: ExprId) -> bool { + pub(crate) fn is_type_assertion(&self, e: ExprId, operand: ExprId) -> bool { self[e].pos < open_parenthesis(self, operand).unwrap_or(self[operand].pos) } /// A `with` statement is stored as a block of its object and its body, positioned at the /// keyword. - fn is_with_statement(&self, s: StmtId) -> bool { + pub(crate) fn is_with_statement(&self, s: StmtId) -> bool { let written = self.text.get(self[s].start as usize..); matches!(self[s].kind, StmtKind::Block(list) if list.len() == 2) && written.is_some_and(|text| text.starts_with(b"with")) @@ -2178,7 +2178,7 @@ impl<'s> File<'s> { fn kind_of_type(&self, t: TypeNodeId, node: Node) -> Kind { match self[t].kind { TypeNodeKind::Error => Kind::Unknown, - TypeNodeKind::Heritage(_) => Kind::ExpressionWithTypeArguments, + TypeNodeKind::Heritage { .. } => Kind::ExpressionWithTypeArguments, TypeNodeKind::Keyword(keyword) => match keyword { Keyword::Any => Kind::AnyKeyword, Keyword::Unknown => Kind::UnknownKeyword, @@ -2274,6 +2274,18 @@ impl<'s> File<'s> { } } + /// `SkipTrivia(text, node.Pos())` for a node whose first token is at `token`, as + /// `GetErrorRangeForNode` and `GetTextOfNode` call it: without `InJSDoc`, so it stops at the `*` + /// before the token (`jsdoc_asterisks`), which `GetTokenPosOfNode` passes over. Not for an + /// identifier, which starts at its token (`createIdentifierWithDiagnostic`). + pub fn skip_trivia_of_node_at(&self, token: u32) -> u32 { + let before = self.jsdoc_asterisks.partition_point(|&at| at < token); + match before.checked_sub(1).map(|last| self.jsdoc_asterisks[last]) { + Some(asterisk) if self.token_after(asterisk + 1) == token => asterisk, + _ => token, + } + } + /// The start of the name of a `MetaProperty` whose keyword ends at `end`. 0 if there is no dot. fn token_after_dot(&self, end: u32) -> u32 { let dot = self.token_after(end); @@ -2307,6 +2319,15 @@ impl<'s> File<'s> { self[t].pos } (Part::Head | Part::Keyword | Part::Opening, NodeData::Expr(e)) => self[e].pos, + (Part::Closing, _) => self.jsx_at(row).map_or(0, |jsx| jsx.close_pos), + // 0 if there are none. + (Part::Attributes, _) => { + let first = self.jsx_at(row).and_then(|jsx| jsx.attrs.iter().next()); + first.map_or(0, |first| self[first].start) + } + (Part::JsxExpression, NodeData::Expr(e)) => { + jsx_expression_around(self, e).map_or(0, |braces| braces.0) + } (Part::Keyword, NodeData::Type(t)) => self[t].pos, (Part::Namespace, _) => self.start(self.parent_of_part(row.with(part))), (Part::LocalName, _) => { @@ -2486,7 +2507,7 @@ impl File<'_> { _ => Node::NONE, }, NodeData::Type(t) => match self[t].kind { - TypeNodeKind::Heritage(e) => self.child(e), + TypeNodeKind::Heritage { expr, .. } => self.child(expr), _ => Node::NONE, }, NodeData::Case(c) => self.child(self[c].test), @@ -3232,11 +3253,15 @@ impl File<'_> { return Ok(is_await); } Kind::PropertyDeclaration if below == self.initializer(above) => return Ok(false), - // Its decorators are parsed in the outer context. + // `parseParameterEx`: its decorators are parsed in the context that + // `parseParametersWorker` found, which `parseType` has exited for a function type. Kind::Parameter if is_await && matches!(self.data(below), NodeData::Modifier(_)) => { above = self.parent(above); + if matches!(self.data(above), NodeData::Type(_)) { + return Ok(false); + } } // The part of an exported class after its type parameters. Kind::ClassDeclaration | Kind::ClassExpression @@ -3271,7 +3296,7 @@ impl File<'_> { } /// Whether `child` is the parameter of the arrow function `x => ..` or `async x => ..`. - fn is_parameter_without_parentheses(&self, arrow_function: Node, child: Node) -> bool { + pub fn is_parameter_without_parentheses(&self, arrow_function: Node, child: Node) -> bool { let (first_token, start) = (self.start(arrow_function), self.start(child)); matches!(self.data(child), NodeData::Param(_)) && (start == first_token diff --git a/src/sema/program.rs b/src/sema/program.rs index 34d748bf30ba..ddd7c8533a65 100644 --- a/src/sema/program.rs +++ b/src/sema/program.rs @@ -6,18 +6,18 @@ mod explain_files; use crate::atom::{Atom, Interner, known}; use crate::bind::{self, Bound, Decl, ScopeId, ScopeKind, SymFlags, Symbol, SymbolId}; -use crate::check::errors::SuggestionLookup; +use crate::check::errors::{SuggestionLookup, is_close}; use crate::check::spans::{Spans, skip_trivia, skip_trivia_back}; use crate::components::Components; use crate::hir::{self, *}; use crate::json::Json; use crate::resolve::{ DiagAndArgs, Host, INFERRED_TYPES_CONTAINING_FILE, JsxEmit, ModuleDetection, ModuleKind, - Options, Phase, ResolvedModule, Resolver, ScriptTarget, Spent, Tracer, ancestors, + Options, PackageId, Phase, ResolvedModule, Resolver, ScriptTarget, Spent, Tracer, ancestors, contains_path, displayed_path, file_extension_is_one_of, file_path, format_by_extension, - get_lib_file_name, has_ts_implementation_extension, inside, is_javascript, is_javascript_file, - is_relative, is_same_path, join, remove_file_extension, supported_extensions, - to_file_name_lower_case, to_path, to_path_in, + get_base_file_name, get_lib_file_name, has_ts_implementation_extension, inside, is_javascript, + is_javascript_file, is_relative, is_same_path, join, path_is_relative, remove_file_extension, + supported_extensions, to_file_name_lower_case, to_path, to_path_in, typescript_path, }; use crate::session::{ Arena, ArenaHashMap, ArenaHashSet, ArenaVec, Session, map_in, set_in, transfer_arena, @@ -145,7 +145,7 @@ pub struct Module<'s> { /// The `package.json` in `PackageJsonDirectory`, if it has no `PackageJsonType`. `NONE` /// otherwise, and unless `module` is `node16` or `node18`: nothing else reads it. pub package_json_without_type: Atom, - /// `SourceFileMetaData.PackageJsonDirectory`: the directory of the `package.json` nearest to + /// `GetNearestAncestorDirectoryWithPackageJson`: the directory of the `package.json` nearest to /// the file. None: there is none. pub package_json_directory: Atom, /// The specifiers that resolve to JavaScript without type declarations, with the resolution @@ -175,14 +175,14 @@ pub struct Module<'s> { /// without `allowArbitraryExtensions`, with the mode they are resolved in. They resolve to no /// file (6263). pub arbitrary_extension_imports: ArenaFew<'s, (Atom, ResolutionMode)>, - /// For each of `arbitrary_extension_imports`: the file it resolves to. + /// For each of `arbitrary_extension_imports`: `ResolvedFileName`. pub arbitrary_extension_files: ArenaFew<'s, Atom>, /// The relative specifiers without an extension, under Node-style module resolution, which /// requires one for `import`; and `getSuggestedImportExtension`, if a candidate file exists. pub extensionless_imports: ArenaFew<'s, (Atom, Option<&'static [u8]>)>, /// `ResolvedFileName` for those of `imports` for which another file is in the program: for a /// duplicate of a package file the copy that is kept, for a source of a referenced project its - /// declaration file. + /// declaration file. And for those for which it is not normalized. pub redirected_imports: ArenaFew<'s, (Atom, ResolutionMode, Atom)>, /// Those of `imports` that resolve to a declaration file of a referenced project, for which its source is loaded. pub project_reference_imports: ArenaFew<'s, (Atom, ResolutionMode)>, @@ -353,20 +353,6 @@ impl Module<'_> { pub fn is_commonjs(&self) -> bool { self.bound.commonjs_indicator.is_some() } - - /// The file that `spec` resolves to in this file, for callers that know the specifier but not - /// its position: its resolution for a plain `import`, or else for whatever use requests it - /// there. Same lookup as `Files::module_of_specifier`. - pub fn imported_file(&self, spec: Atom) -> Option { - [ - self.default_mode, - ResolutionMode::Import, - ResolutionMode::Require, - ResolutionMode::None, - ] - .into_iter() - .find_map(|mode| self.imports.get(&(spec, mode)).copied()) - } } /// `ast.SymbolTable`. Iteration is in insertion order, which is the same in every run. @@ -561,8 +547,11 @@ pub struct Files<'s> { /// The modules with one of `ModuleSymbolLinks::export_collisions` in another file. Filled by /// `link`. pub modules_with_nested_export_collisions: &'s [Sym], + /// By file and identifier, the runs for one identifier in the order in which they began. Filled + /// by `link`. + failed_lookups: &'s [FailedLookup<'s>], /// `symbol.Parent` of a transient symbol, where `mergeSymbolTable` has set it to a symbol of - /// another file: the module through which an augmentation has reached the target of an alias. + /// another file. parents_in_other_files: ArenaHashMap<'s, Sym, Sym>, /// Some file contains `export type * from`. @@ -576,6 +565,8 @@ pub struct Files<'s> { no_module_links: ModuleSymbolLinks<'s>, /// The symbol merge is done: symbols no longer change. is_merged: bool, + /// Some alias has a `combined_symbol`. + has_symbols_to_combine: bool, memo: Memo<'s>, /// The file order in which declarations of one symbol in several files are considered: it /// determines the order of overloads. @@ -586,13 +577,17 @@ pub struct Files<'s> { pub components: Components<'s>, /// `global_type` of every name below `known::sym_iterator`, indexed by atom number. global_types: &'s [GlobalType], + /// The global `Array` or `ReadonlyArray` declares a member whose name begins with a digit. Only + /// then can `T[][0]` be anything but `T`. + pub arrays_have_numeric_members: bool, /// Errors in what the options refer to, not attributable to any file. program_errors: &'s [Problem], /// `GetIncludeProcessorDiagnostics`: errors about the inclusion of a file in the program, /// reported at the reference in another file: that file and the span. include_errors: &'s [(FileId, u32, u32, Problem)], - /// The `package.json` of each `node_modules` package that contains a file of the program, keyed - /// by its directory. Declaration files and messages need module specifiers for such files. + /// The `package.json` of each `node_modules` package that contains a file of the program, and + /// the one in `Module::package_json_directory` of each file, keyed by its directory. + /// Declaration files and messages need module specifiers from their `exports` and `imports`. pub package_jsons: ArenaHashMap<'s, &'s [u8], &'s Json>, /// `DirectoriesByRealpath`: each directory that is known to be a symlink target, with a symlink /// to it, in order. The `package.json` of each is in `package_jsons` under the path of the @@ -611,6 +606,8 @@ pub struct Files<'s> { /// `redirectFilesByPath`, in the order in which `collectFiles` comes to them: the name of a copy /// of a package file, and the copy that is in the program. package_copies: &'s [(&'s [u8], FileId)], + /// `Included::explained_in_diagnostics` of the errors that `load` has made. + explained_in_diagnostics: &'s [Vec], } /// `Files::global_type` @@ -643,6 +640,9 @@ pub struct ExportCollision { /// The `export *` that exported it first. `specifierText` is its specifier. pub first: (FileId, StmtId), pub name: Atom, + /// `targetSymbol` and `sourceSymbol`, where only types tell whether `resolveSymbol` of both is + /// one symbol (`Resolve::may_need_types_to_resolve`). If it is, there is no error. + pub symbols: Option<(Sym, Sym)>, } /// `ModuleSymbolLinks`. In the arena of the thread that computes them. @@ -755,6 +755,8 @@ struct Resolution<'r> { should_add_file: bool, /// `increaseDepth` increases_depth: bool, + /// `packageId` of the task for `path`. `redirectedParseTask` has none. + package_id: Option>, /// `resolveExternalModule` asks `GetSourceFileForResolvedModule` for it. Otherwise it resolves /// to no file, even if the file is in the program. is_importable: bool, @@ -767,14 +769,16 @@ struct Resolution<'r> { struct Loaded<'s, 'r> { module: Module<'s>, imports: Vec>, - /// (path, is a lib, `increaseDepth`) - references: Vec<(&'r [u8], bool, bool)>, + /// (path, is a lib, `increaseDepth`, `packageId`) + references: Vec<(&'r [u8], bool, bool, Option>)>, /// The `/// ` to a library that is replaced by a file with an extension that /// the program does not support: its span, the file, and the error of `parseTask.load`. The /// file is not read. unsupported_libs: Vec<(u32, u32, &'r [u8], u32)>, - /// `typeResolutionsTrace`, then `resolutionsTrace` - traces: Vec, + /// `typeResolutionsTrace` + type_resolutions_trace: Vec, + /// `resolutionsTrace` + resolutions_trace: Vec, } /// A file that `Files::load` has found. @@ -782,7 +786,7 @@ struct Loaded<'s, 'r> { struct FoundFile<'s> { path: Path<'s>, is_lib: bool, - /// `parseTaskData.packageId`, as an index into `Found::kept`. + /// `parseTaskData.packageId`, of `first`, as an index into `Found::kept`. package: Option, /// `taskDataByPath`: the first task for the file, by whichever spelling of its name. first: FileId, @@ -803,6 +807,8 @@ struct SubTask { increases_depth: bool, /// `elideOnDepth` is_elided_on_depth: bool, + /// `packageId`: `Found::package_of_task`. + package: Option, } /// What `Files::load` knows about the files it has found, besides the files themselves. @@ -810,23 +816,26 @@ struct SubTask { struct Found<'s> { /// By `FileId`. files: Vec>, - /// The index in `kept` for a `Resolver::package_id`. + /// The index in `kept` for a `PackageId`. by_package_id: FxHashMap, u32>, /// `packageIdToSourceFile`: the copy of a package file that `collectFiles` came to first. kept: Vec>, - /// Whether `collectFiles` has begun. - is_collecting: bool, } impl Found<'_> { - /// The index in `kept` for `package_id`, and whether no file has had that id before. - fn package(&mut self, package_id: Vec) -> (u32, bool) { + /// `package_id` of a task for `file`, as an index into `kept`. `None` as well if the file has + /// an id, which it keeps. + fn package_of_task(&mut self, file: FileId, package_id: Option) -> Option { + let data = self.files[file.idx()].first; + let id = package_id.filter(|_| self.files[data.idx()].package.is_none())?; + let (version, peers) = (id.version, id.peer_dependencies); + let key = [id.name, b"@", version, peers, b"/", id.sub_module_name].concat(); let new = self.kept.len() as u32; - let index = *self.by_package_id.entry(package_id).or_insert(new); + let index = *self.by_package_id.entry(key).or_insert(new); if index == new { self.kept.push(None); } - (index, index == new) + Some(index) } } @@ -944,6 +953,16 @@ pub struct AliasSymbolLinks { pub ran_out_of_stack: bool, } +/// A run of `getResolvedSymbol` that finds nothing, for the first identifier of an expression that +/// `getTargetOfAliasLikeExpression` checks. Each run reports, with the spelling suggestion it finds. +#[derive(Copy, Clone)] +pub struct FailedLookup<'s> { + pub file: FileId, + pub identifier: ExprId, + /// The aliases for which `tryResolveAlias` returns nil during the run. + pub aliases_in_progress: &'s [Sym], +} + /// The functions that resolve names, exports and aliases. Each of them can call `alias_links`, and /// `alias_links` can call each of them. /// @@ -970,6 +989,18 @@ trait Resolve<'s>: std::ops::Deref> { /// Sets `ObjectFlagsMembersResolved` of the type of `symbol`. Returns whether it was not set. fn set_members_resolved(&self, symbol: Sym) -> bool; + /// `findResolutionCycleStartIndex(sym, TypeSystemPropertyNameAliasTarget) >= 0` + fn is_alias_in_progress(&self, sym: Sym) -> bool; + + /// `symbolNodeLinks.Get(node).resolvedSymbol != nil` for the identifier `e` of `file`. + fn has_resolved_symbol(&self, file: FileId, e: ExprId) -> bool; + + /// Sets `resolvedSymbol` of the identifier `e` of `file`. + fn set_resolved_symbol(&self, file: FileId, e: ExprId); + + /// A `FailedLookup` for the identifier `e` of `file` begins. + fn note_failed_lookup(&self, file: FileId, e: ExprId); + /// `getSymbol`: whether `sym`, found under a name, matches the requested `meaning`. An alias /// has the combined meanings of itself and of every symbol on the chain to its target. fn means(&self, sym: Sym, meaning: SymFlags) -> bool { @@ -1139,6 +1170,7 @@ trait Resolve<'s>: std::ops::Deref> { { return Some(found); } + self.resolve_export_by_name(module, known::default); if let Some(synthesized) = self.synthetic_default(file, module) { return Some(synthesized); } @@ -1316,15 +1348,20 @@ trait Resolve<'s>: std::ops::Deref> { lookup_table.insert(name, node); continue; }; + let is_one_symbol = self.resolve_symbol(target) == self.resolve_symbol(source); // The module's own exports take precedence. - if self.resolve_symbol(target) != self.resolve_symbol(source) - && name != known::export_equals - && !symbols.contains_key(name) - { + if name == known::export_equals || symbols.contains_key(name) { + continue; + } + let needs_types = target != source + && (self.may_need_types_to_resolve(target) + || self.may_need_types_to_resolve(source)); + if needs_types || !is_one_symbol { visit.export_collisions.push(ExportCollision { duplicate: node, first: lookup_table[&name], name, + symbols: needs_types.then_some((target, source)), }); } } @@ -1354,6 +1391,30 @@ trait Resolve<'s>: std::ops::Deref> { } } + /// Whether `resolveSymbol(sym)` may be a symbol that the tables do not have, which + /// `Checker::resolve_alias` finds from types: for `sym` or an alias on the chain to its target, + /// `resolveESModuleSymbol` or `combineValueAndTypeSymbols` may create one, or the target may be + /// a property. + fn may_need_types_to_resolve(&self, mut sym: Sym) -> bool { + for _ in 0..32 { + if !self.is_non_local_alias(sym) { + return false; + } + if matches!( + self.declaration_of_alias_symbol(sym), + Some((_, Decl::ImportNamespace(_) | Decl::ExportStarAs(_))) + ) || self.is_named_import_from_export_equals(sym) + { + return true; + } + match self.alias_target(sym) { + Some(next) if next != sym => sym = next, + next => return next.is_none(), + } + } + false + } + /// `typeOnlyExportStarMap[name]` of `module`: the `export type *` that is the only path through /// which it exports `name`. fn type_only_export_star(&self, module: Sym, name: Atom) -> Option<(FileId, StmtId)> { @@ -1480,26 +1541,32 @@ trait Resolve<'s>: std::ops::Deref> { self.resolve_alias_as_with(sym, meaning, &mut InTables(self)) } - /// `tryResolveAlias(candidate)`, for a spelling suggestion for an unresolved name in the alias - /// declaration at `asking`. It skips an alias whose resolution is in progress, so the result - /// depends on which resolution started first. tsgo resolves them in source order: an alias - /// declared before `asking` is resolved or in progress, and is left alone. An alias declared - /// after it has not been started. If it has been started here, by a caller that entered through - /// it, it is in a cycle with `asking`, as if `asking` had been first. - fn try_resolve_alias(&self, asking: (FileId, u32), candidate: Sym) -> Option { - let (file, decl) = self.declaration_of_alias_symbol(candidate)?; - ((file, self.start_of_declaration(file, decl)) > asking) - .then(|| self.alias_links(candidate)) + /// `tryResolveAlias` + fn try_resolve_alias(&self, symbol: Sym) -> Option { + (!self.is_alias_in_progress(symbol)).then(|| self.alias_links(symbol)) + } + + /// `getResolvedSymbol` of the identifier `e` in `scope` of `file`, limited to its side effects + /// on aliases. While the name is looked up it has no `resolvedSymbol`: an alias that the lookup + /// resolves can come here again. + fn get_resolved_symbol(&self, file: FileId, e: ExprId, scope: ScopeId, name: Atom) { + if self.has_resolved_symbol(file, e) { + return; + } + let value = SymFlags::VALUE | SymFlags::EXPORT_VALUE; + if self.resolve_name(file, scope, name, value).is_none() { + self.note_failed_lookup(file, e); + self.on_failed_to_resolve_symbol(file, scope, name, value); + } + self.set_resolved_symbol(file, e); } /// `onFailedToResolveSymbol`, limited to its side effects on aliases: `getSymbol` resolves an /// alias of that name that has not the meaning itself, and `getSpellingSuggestionForName` /// every alias it inspects. - /// `decl`: the alias declaration in `file` that contains the name. fn on_failed_to_resolve_symbol( &self, file: FileId, - decl: Decl, scope: ScopeId, name: Atom, meaning: SymFlags, @@ -1547,10 +1614,6 @@ trait Resolve<'s>: std::ops::Deref> { { return; } - let symbols = &mut InAliasDeclaration { - resolver: self, - asking: (file, self.start_of_declaration(file, decl)), - }; let name = (name, self.atoms.bytes(name)); // For the aliases that the search resolves. The suggestion is for the error, which the // checker reports. @@ -1558,7 +1621,7 @@ trait Resolve<'s>: std::ops::Deref> { Some((file, scope)), name, meaning, - symbols, + &mut InTables(self), None, ); } @@ -1576,11 +1639,11 @@ trait Resolve<'s>: std::ops::Deref> { } /// `resolveESModuleSymbol`, limited to what the symbol tables can answer. - /// `is_namespace_import`: `namespaceImport != nil`. + /// `namespace_import_in`: the file, if `namespaceImport != nil`. fn resolve_es_module_symbol( &self, module: Sym, - is_namespace_import: bool, + namespace_import_in: Option, type_only: &mut Option, ) -> Sym { let mut symbol = self.external_module_symbol(module); @@ -1589,31 +1652,56 @@ trait Resolve<'s>: std::ops::Deref> { // does so one step at a time. symbol = (self.resolve_indirection_alias(symbol, type_only)).unwrap_or(symbol); } + let Some(file) = namespace_import_in else { + return symbol; + }; + // `getTypeWithSyntheticDefaultOnly`: the only member is the synthetic `default`. + if self.is_only_importable_as_default(file, module) { + return symbol; + } // `hasSignatures(getTypeOfSymbol(symbol))` - if is_namespace_import { - self.resolve_members_of_type_of_symbol(symbol); + self.resolve_members_of_type_of_symbol(symbol); + if !self.has_exports_for_members(symbol) || self.is_shorthand_ambient_module_symbol(symbol) + { + return symbol; + } + let has_signatures = SymFlags::FUNCTION | SymFlags::METHOD | SymFlags::CLASS; + let has_signatures = self.flags(symbol).intersects(has_signatures); + // Whether `cloneTypeAsModuleType` is called with the type itself. With a synthetic default + // the members of `moduleType` are the properties of the type, which are resolved, or none + // while it is being resolved. + let is_cloned = if self.is_commonjs_import_of_esm_file(file, module) + && self.module_exports_export(symbol).is_some() + { + has_signatures + } else { + (has_signatures + || self.type_of_symbol_has_property(symbol, known::default) + || self.is_commonjs_to_node(file, module)) + && self.synthetic_default(file, module).is_none() + }; + // `newAnonymousType` has no `ObjectFlagsMembersResolved` to ask. + if is_cloned { + self.get_named_members(symbol); } symbol } /// `resolveStructuredTypeMembers(getTypeOfSymbol(symbol))`, limited to what it does to aliases, - /// and to a type whose members are the exports of `symbol`: `getNamedMembers` asks - /// `symbolIsValue` of each, which resolves it if it is an alias. + /// and to a type whose members are the exports of `symbol`. fn resolve_members_of_type_of_symbol(&self, symbol: Sym) { - let flags = self.flags(symbol); - // `getTypeOfFuncClassEnumModule` - let has_exports_for_members = SymFlags::FUNCTION - | SymFlags::METHOD - | SymFlags::CLASS - | SymFlags::ENUM - | SymFlags::VALUE_MODULE; - if flags.intersects(SymFlags::VARIABLE | SymFlags::PROPERTY) - || !flags.intersects(has_exports_for_members) - || !self.set_members_resolved(symbol) - || self.is_shorthand_ambient_module_symbol(symbol) + if self.has_exports_for_members(symbol) + && self.set_members_resolved(symbol) + && !self.is_shorthand_ambient_module_symbol(symbol) { - return; + self.get_named_members(symbol); } + } + + /// `getNamedMembers(getExportsOfSymbol(symbol), ..)`, limited to what it does to aliases: it + /// asks `symbolIsValue` of each, which resolves it if it is an alias. + fn get_named_members(&self, symbol: Sym) { + let flags = self.flags(symbol); let is_alias_only = |export: Sym| { let flags = self.flags(export); flags.contains(SymFlags::ALIAS) && !flags.intersects(SymFlags::VALUE) @@ -1633,11 +1721,102 @@ trait Resolve<'s>: std::ops::Deref> { } } + /// `getTypeOfFuncClassEnumModule`: whether the members of `getTypeOfSymbol(symbol)` are the + /// exports of `symbol`. + fn has_exports_for_members(&self, symbol: Sym) -> bool { + let flags = self.flags(symbol); + let has_exports = SymFlags::FUNCTION + | SymFlags::METHOD + | SymFlags::CLASS + | SymFlags::ENUM + | SymFlags::VALUE_MODULE; + !flags.intersects(SymFlags::VARIABLE | SymFlags::PROPERTY) && flags.intersects(has_exports) + } + + /// `resolveExportByName`, limited to what it does to aliases, which is nothing unless `module` + /// has `export =`: `getPropertyOfTypeEx(getTypeOfSymbol(exportValue), name, ..)` resolves the + /// members of the type, and asks `symbolIsValueEx` of the member `name`. + fn resolve_export_by_name(&self, module: Sym, name: Atom) { + if self.export(module, known::export_equals).is_none() { + return; + } + let value = self.module_value(module); + if !self.has_exports_for_members(value) { + return; + } + self.resolve_members_of_type_of_symbol(value); + self.type_of_symbol_has_property(value, name); + } + + /// `getPropertyOfTypeEx(getTypeOfSymbol(symbol), name, ..) != nil`, where the members of the + /// type are resolved and are the exports of `symbol`. + fn type_of_symbol_has_property(&self, symbol: Sym, name: Atom) -> bool { + // `getExportsOfSymbol` + let member = if self.flags(symbol).intersects(SymFlags::MODULE) { + self.module_export(symbol, name) + } else { + self.export(symbol, name) + }; + // `symbolIsValueEx` + member.is_some_and(|member| { + let value = SymFlags::VALUE; + self.flags(member).intersects(value) + || self.symbol_flags_ex(member, true, false).intersects(value) + }) + } + /// `getImmediateAliasedSymbol` fn alias_target(&self, sym: Sym) -> Option { self.alias_links(sym).immediate_target } + /// `errorNoModuleMemberSymbol` for `name`, which `decl` of `file` imports from `module`, + /// limited to its side effects on aliases: `reportNonExportedMember` resolves the local symbol + /// of that name, and the exports it is compared with (`getSymbolIfSameReference`). Not with an + /// `export =`, where types tell whether there is a member. + fn error_no_module_member_symbol(&self, file: FileId, decl: Decl, module: Sym, name: Atom) { + if self.options.no_check + || self.export(module, known::export_equals).is_some() + || !matches!(decl, Decl::Require(_)) + && self.is_only_importable_as_default(self.emit_syntax_of_import(file), module) + { + return; + } + // `getSuggestedSymbolForNonexistentModule`: for an identifier, not for a string literal. + let hir = self.hir(file); + let start = match decl { + Decl::ImportSpec(s) => hir[s].imported_pos, + Decl::ExportSpec(s) => hir[s].local_pos, + _ => u32::MAX, + }; + let is_identifier = !matches!(hir.text.get(start as usize), Some(b'"' | b'\'')); + let text = self.atoms.bytes(name); + let is_suggestion = |&(other, exported): &(Atom, Sym)| { + self.flags(exported).intersects(SymFlags::MODULE_MEMBER) + && is_close(text, self.atoms.bytes(other)) + }; + let has_suggestion = is_identifier + && self.with_exports_of_module(module, |links| { + links.resolved_exports.iter().any(is_suggestion) + }); + if has_suggestion || self.export(module, known::default).is_some() { + return; + } + let Some(local) = self.local_of_module(module, name) else { + return; + }; + let resolved = |symbol: Sym| { + let resolved = self.resolve_symbol(self.canonical(symbol)); + resolved.map(|resolved| self.canonical(resolved)) + }; + // `findInMap`. The entry for the `export *` declarations is no alias. + let exports = self.exports(module); + let is_exported = (exports.iter()).any(|&(_, it)| resolved(it) == resolved(local)); + if !is_exported && !self.export_stars_of(module).is_empty() { + resolved(local); + } + } + /// `getTargetOfAliasDeclaration` for the declaration `decl` in `file` of `sym`: one step, to a /// symbol that may itself be an alias. /// `type_only`: `typeOnlyDeclaration` of `sym`. @@ -1663,7 +1842,7 @@ trait Resolve<'s>: std::ops::Deref> { return self.default_of_module(file, module); } // `getExternalModuleMember`, `getExportOfModule` - self.resolve_es_module_symbol(module, false, type_only); + self.resolve_es_module_symbol(module, None, type_only); // `nameText != "" || name.Kind == KindStringLiteral` if name.is_none() { return None; @@ -1673,7 +1852,11 @@ trait Resolve<'s>: std::ops::Deref> { } let star = self.type_only_export_star(module, name); self.mark_symbol_of_alias_declaration_if_type_only(node, star, type_only); - self.module_export_in_table(module, name) + let member = self.module_export_in_table(module, name); + if member.is_none() { + self.error_no_module_member_symbol(file, decl, module, name); + } + member }); self.mark_symbol_of_alias_declaration_if_type_only(node, None, type_only); return target; @@ -1698,8 +1881,8 @@ trait Resolve<'s>: std::ops::Deref> { .map(|module| { // The `JSImportDeclaration` of an `@import` tag is no `ImportDeclaration`. let is_import_declaration = !hir.is_in_jsdoc(hir[import].namespace_pos); - let symbol = - self.resolve_es_module_symbol(module, is_import_declaration, type_only); + let import_in = is_import_declaration.then_some(file); + let symbol = self.resolve_es_module_symbol(module, import_in, type_only); if self.is_commonjs_import_of_esm_file(file, module) && let Some(found) = self.module_exports_export(symbol) { @@ -1743,13 +1926,8 @@ trait Resolve<'s>: std::ops::Deref> { .resolve_name(file, scope, names[0], SymFlags::NAMESPACE) .is_none() { - self.on_failed_to_resolve_symbol( - file, - decl, - scope, - names[0], - SymFlags::NAMESPACE, - ); + let namespace = SymFlags::NAMESPACE; + self.on_failed_to_resolve_symbol(file, scope, names[0], namespace); } return target; } @@ -1767,7 +1945,7 @@ trait Resolve<'s>: std::ops::Deref> { let scope = bound.export_scope[hir[spec].export.idx()]; let target = self.resolve_name(file, scope, hir[spec].local, all); if target.is_none() { - self.on_failed_to_resolve_symbol(file, decl, scope, hir[spec].local, all); + self.on_failed_to_resolve_symbol(file, scope, hir[spec].local, all); } target } @@ -1787,7 +1965,7 @@ trait Resolve<'s>: std::ops::Deref> { return None; }; self.module_of_specifier_as(file, spec, self.mode_of_import(file, mode)) - .map(|module| self.resolve_es_module_symbol(module, false, type_only)) + .map(|module| self.resolve_es_module_symbol(module, None, type_only)) } // `getTargetOfImportEqualsDeclaration`: the whole required module. Decl::Require(pat) => { @@ -1851,23 +2029,35 @@ trait Resolve<'s>: std::ops::Deref> { names.reverse(); let scope = *bound.expr_scope.get(&e)?; let target = self.resolve_entity(file, scope, &names, all); - // `checkExpressionCached(expression)`: `getResolvedSymbol` of the first name. For an - // `ExportAssignment`, `checkExportAssignment` has cached it before. - let value = SymFlags::VALUE | SymFlags::EXPORT_VALUE; - if target.is_none() - && !matches!(decl, Decl::ExportExpr(_)) - && self.resolve_name(file, scope, names[0], value).is_none() - { - self.on_failed_to_resolve_symbol(file, decl, scope, names[0], value); + // `checkExpressionCached(expression)` + if target.is_none() { + self.get_resolved_symbol(file, at, scope, names[0]); } target } _ => None, } } + + /// `checkExportAssignment` of the statement `stmt`, limited to its side effects on aliases. + fn check_export_assignment(&self, file: FileId, stmt: StmtId) { + // `checkGrammarModuleElementContext`, and 1063 or 1319 in a namespace. + let is_checked = match self.bound(file).stmt_parent.get(stmt.idx()) { + Some(bind::Parent::File) => true, + Some(bind::Parent::Module(m)) => { + !matches!(self.hir(file)[*m].name, ModuleName::Ident(_)) + } + _ => false, + }; + // `resolveEntityName`, then `checkExpressionCached` of what is not found: here no alias is + // in progress for it. + if is_checked { + self.target_of_alias_like_expression(file, Decl::ExportExpr(stmt)); + } + } } -/// `EntityNameLookup` as far as the symbol tables can answer. +/// `EntityNameLookup` and `SuggestionLookup` as far as the symbol tables can answer. struct InTables<'a, R: ?Sized>(&'a R); impl<'s, R: Resolve<'s> + ?Sized> EntityNameLookup for InTables<'_, R> { @@ -1880,22 +2070,15 @@ impl<'s, R: Resolve<'s> + ?Sized> EntityNameLookup for InTables<'_, R> { } } -/// For an unresolved name in the alias declaration at `asking`. -struct InAliasDeclaration<'a, R: ?Sized> { - resolver: &'a R, - asking: (FileId, u32), -} - -impl<'s, R: Resolve<'s> + ?Sized> SuggestionLookup for InAliasDeclaration<'_, R> { +impl<'s, R: Resolve<'s> + ?Sized> SuggestionLookup for InTables<'_, R> { fn get_symbol(&mut self, held: Option, meaning: SymFlags) -> Option { - held.filter(|&sym| self.resolver.means(sym, meaning)) + held.filter(|&sym| self.0.means(sym, meaning)) } fn try_resolve_alias(&mut self, candidate: Sym) -> Option { - let InAliasDeclaration { resolver, asking } = *self; - let target = resolver.try_resolve_alias(asking, candidate)?.alias_target; + let target = self.0.try_resolve_alias(candidate)?.alias_target; // `unknownSymbol` - Some(target.map_or(SymFlags::PROPERTY, |target| resolver.flags(target))) + Some(target.map_or(SymFlags::PROPERTY, |target| self.0.flags(target))) } } @@ -1940,6 +2123,18 @@ impl<'s> Resolve<'s> for Linked<'_, 's> { fn set_members_resolved(&self, _: Sym) -> bool { false } + + fn is_alias_in_progress(&self, _: Sym) -> bool { + false + } + + fn has_resolved_symbol(&self, _: FileId, _: ExprId) -> bool { + true + } + + fn set_resolved_symbol(&self, _: FileId, _: ExprId) {} + + fn note_failed_lookup(&self, _: FileId, _: ExprId) {} } /// `Resolve` while the tables are filled. tsgo pushes `TypeSystemPropertyNameAliasTarget` on @@ -1966,6 +2161,9 @@ struct AliasResolver<'a, 's> { arena: std::cell::OnceCell<&'s Arena>, /// The symbols whose type has `ObjectFlagsMembersResolved`. members_resolved: std::cell::RefCell>, + /// The identifiers that have a `resolvedSymbol`, of those that `get_resolved_symbol` is asked + /// for. + resolved_symbols: std::cell::RefCell>, } /// The write buffer of a task of the link step. It is dropped at the barrier after the step. What @@ -1976,6 +2174,7 @@ struct Resolved<'s> { symbol_flags: FxHashMap, module_links: FxHashMap>, decls: Vec<(Sym, &'s [(FileId, Decl)])>, + failed_lookups: Vec>, } impl<'s> std::ops::Deref for AliasResolver<'_, 's> { @@ -2115,23 +2314,73 @@ fn dynamic_imports<'a>(hir: &'a hir::File) -> Vec<&'a SpecifierUse> { found } +/// `collectModuleReferences`: `IsAmbientModule(node) && (inAmbientModule || +/// HasSyntacticModifier(node, ModifierFlagsAmbient) || file.IsDeclarationFile)` +fn ambient_module(hir: &hir::File, s: StmtId, is_in_ambient_module: bool) -> Option { + let StmtKind::Module(m) = hir[s].kind else { + return None; + }; + let is_ambient = is_in_ambient_module + || hir[m].flags.contains(Flags::AMBIENT) + || hir.kind == FileKind::Declaration; + (is_ambient && !matches!(hir[m].name, ModuleName::Ident(_))).then_some(m) +} + +/// `collectModuleReferences`: the import and export statements that it visits, in order. Of each +/// where it starts and ends, and `inAmbientModule`. They are the statements of the file, and in a +/// script those of the ambient modules that it declares. It visits neither a module augmentation +/// nor a namespace. +fn module_references(hir: &hir::File) -> Vec<(u32, u32, bool)> { + let mut references = Vec::new(); + let mut visit = |s: StmtId, is_in_ambient_module: bool| { + // `IsAnyImportOrReExport` + let is_one = matches!( + hir[s].kind, + StmtKind::Import(_) + | StmtKind::ImportEquals(_) + | StmtKind::ExportNamed(_) + | StmtKind::ExportStar { .. } + ); + if is_one { + references.push((hir[s].start, hir[s].loc.end, is_in_ambient_module)); + } + is_one + }; + for s in hir.ids(hir.body) { + if !visit(s, false) + && !hir.has_module_syntax + && let Some(m) = ambient_module(hir, s, false) + { + for s in hir.ids(hir[m].body) { + visit(s, true); + } + } + } + // The one for an `@import` inside a statement comes before that statement. + references.sort_unstable(); + references +} + +/// Whether `u` is one of `file.Imports()`. `visited`: the `module_references` of the file. +fn is_among_imports(visited: &[(u32, u32, bool)], atoms: &Interner, u: &SpecifierUse) -> bool { + // `ForEachDynamicImportOrRequireCall` looks at the whole text. + if u.kind.is_dynamic() { + return u.spec.is_some(); + } + let after = visited.partition_point(|statement| statement.0 <= u.pos); + after.checked_sub(1).is_some_and(|at| { + let (_, end, is_in_ambient_module) = visited[at]; + // "Relative external module names are not permitted." + u.pos < end && !(is_in_ambient_module && is_relative(atoms.bytes(u.spec))) + }) +} + /// `file.ModuleAugmentations` (`collectModuleReferences`): the declarations that they are the names /// of. fn module_augmentations(hir: &hir::File, atoms: &Interner) -> Vec { - // `IsAmbientModule(node) && (inAmbientModule || HasSyntacticModifier(node, ModifierFlagsAmbient) - // || file.IsDeclarationFile)` - let ambient_module = |s: StmtId, is_in_ambient_module: bool| { - let StmtKind::Module(m) = hir[s].kind else { - return None; - }; - let is_ambient = is_in_ambient_module - || hir[m].flags.contains(Flags::AMBIENT) - || hir.kind == FileKind::Declaration; - (is_ambient && !matches!(hir[m].name, ModuleName::Ident(_))).then_some(m) - }; let mut augmentations = Vec::new(); for s in hir.ids(hir.body) { - let Some(m) = ambient_module(s, false) else { + let Some(m) = ambient_module(hir, s, false) else { continue; }; if hir.has_module_syntax { @@ -2139,7 +2388,7 @@ fn module_augmentations(hir: &hir::File, atoms: &Interner) -> Vec { continue; } let nested = hir.ids(hir[m].body); - let nested = nested.filter_map(|s| ambient_module(s, true)); + let nested = nested.filter_map(|s| ambient_module(hir, s, true)); augmentations.extend(nested.filter(|&nested| { !matches!(hir[nested].name, ModuleName::String(name) if is_relative(atoms.bytes(name))) })); @@ -2157,8 +2406,15 @@ fn merges_module_augmentation(bound: &Bound, collected: &[ModuleId], symbol: Sym ) } -/// `getLibraryNameFromLibFileName` and `getInferredLibraryNameResolveFrom` -fn library_name_and_resolve_from(options: &Options, lib: &[u8]) -> (Vec, Vec) { +/// What `resolveLibrary` is called with. +struct LibraryName { + /// `getLibraryNameFromLibFileName` + name: Vec, + /// `getInferredLibraryNameResolveFrom` + from: Vec, +} + +fn library_name_and_resolve_from(options: &Options, lib: &[u8]) -> LibraryName { // `dom.iterable` is `@typescript/lib-dom/iterable`, `es2015.symbol.wellknown` is // `@typescript/lib-es2015/symbol-wellknown`. let mut name = b"@typescript/lib-".to_vec(); @@ -2177,7 +2433,7 @@ fn library_name_and_resolve_from(options: &Options, lib: &[u8]) -> (Vec, Vec b".d.ts__.ts", ] .concat(); - (name, from) + LibraryName { name, from } } /// `pathForLibFile`: the path `lib..d.ts` is read from. The task for it has a `libFile`, @@ -2185,7 +2441,7 @@ fn library_name_and_resolve_from(options: &Options, lib: &[u8]) -> (Vec, Vec fn lib_path(resolver: &Resolver, options: &Options, lib: &[u8]) -> Vec { // `name != "lib.d.ts"` if options.lib_replacement && !lib.is_empty() { - let (name, from) = library_name_and_resolve_from(options, lib); + let LibraryName { name, from } = library_name_and_resolve_from(options, lib); // `resolveLibrary`: always resolved the way `require` resolves. if let Some(found) = resolver.resolve_module_name(&name, &from, ResolutionMode::Require) { return found.file_name.to_vec(); @@ -2194,6 +2450,33 @@ fn lib_path(resolver: &Resolver, options: &Options, lib: &[u8]) -> Vec { lib_file(options, lib) } +/// `pathForLibFile`, as far as `traceResolution` shows it. The first time it is asked for `lib`, the +/// lookups of the resolution go through `cache`, and `libResolution.trace` is put into +/// `resolutions` (`pathForLibFileResolutions`), which is in the order of its keys. +fn trace_path_for_lib_file( + host: &dyn Host, + resolver: &Resolver, + options: &Options, + lib: &[u8], + cache: &mut PackageJsonInfoCache, + resolutions: &mut Vec<(Vec, Vec)>, +) { + // `name != "lib.d.ts"` + if !options.lib_replacement || lib.is_empty() { + return; + } + let LibraryName { name, from } = library_name_and_resolve_from(options, lib); + let key = to_path(&from, host.is_case_sensitive()).into_owned(); + let Err(at) = resolutions.binary_search_by(|known| known.0.cmp(&key)) else { + return; + }; + let tracer = Tracer::default(); + resolver.resolve_module_name_traced(&name, &from, ResolutionMode::Require, Some(&tracer)); + let mut trace = tracer.into_traces(); + cache.get_package_json_infos(host, &mut trace); + resolutions.insert(at, (key, trace)); +} + /// The tasks of `processAllProgramFiles` for the libraries: for each of `Options::libs` its reason, /// `pathForLibFile`, and the error of `parseTask.load` for the extension of a file that replaces it. /// Such a file is not read. @@ -2335,18 +2618,21 @@ fn automatic_type_directives( let mut names = host.list_dir(&root); names.sort_unstable(); for name in names { - let dir = [&root[..], b"/", &name[..]].concat(); - if name.starts_with(b".") || !host.is_dir(&dir) { + if !host.is_dir(&inside(&root, &name)) { continue; } + // `CombinePaths(root, normalized)`: a name can be a root (`c:`) or have a `\`. + let dir = join(&root, &name); // `Typings.Null`: `"typings": null` is how a package declares that it is not needed. // It holds whatever value follows for the same name. let is_not_needed_package = resolver.package_json(&dir).is_some_and(|fields| { let mut fields = fields.as_object().unwrap_or_default().iter(); fields.any(|field| field.0 == b"typings" && field.1 == Json::Null) }); - if !is_not_needed_package { - packages.push(name); + let normalized = join(b"/", &name); + let base_file_name = get_base_file_name(typescript_path(&normalized)); + if !is_not_needed_package && !base_file_name.starts_with(b".") { + packages.push(base_file_name.to_vec()); } } } @@ -2521,7 +2807,7 @@ fn times_among_imports(hir: &File, calls: &ExprsByKind, text: &[u8], u: &Specifi let start = start_of(hir, call); let is_first = |s: &Stmt| matches!(s.kind, StmtKind::Expr(e) if start_of(hir, e) == start); if hir.is_js && hir.stmts.iter().any(is_first) { - times += count_outside_jsdoc(&text[at..start as usize]); + times += count_after_jsdoc(&text[at..start as usize]); at = start as usize; } for (from, to) in hir.ids(args).filter(|e| !is_token(e)).map(range) { @@ -2531,9 +2817,15 @@ fn times_among_imports(hir: &File, calls: &ExprsByKind, text: &[u8], u: &Specifi (times + count_import_or_require(&text[at..end.max(at)])).max(1) } -/// `count_import_or_require` in `trivia`, but for the comments `/** */` in it. -fn count_outside_jsdoc(trivia: &[u8]) -> usize { - let (mut at, mut count) = (0, 0); +/// `count_import_or_require` in `trivia`, after the last `/** */` in it. `withJSDoc`: a `JSDoc` +/// begins where the one before it ends, and the first one where its host begins. +fn count_after_jsdoc(trivia: &[u8]) -> usize { + // `isShebangTrivia` + let mut at = match trivia.starts_with(b"#!") { + true => strings::index_of_any(trivia, b"\n\r").unwrap_or(trivia.len()), + false => 0, + }; + let mut end_of_jsdoc = 0; while let Some(next) = strings::index_of_char_usize(&trivia[at..], b'/') { at += next; let rest = &trivia[at..]; @@ -2543,13 +2835,13 @@ fn count_outside_jsdoc(trivia: &[u8]) -> usize { strings::index_of(&rest[2.min(rest.len())..], b"*/").map_or(rest.len(), |it| it + 4) } }; + at += end.max(1); // `/**/` is not one. - if !(rest.starts_with(b"/**") && end > 4) { - count += count_import_or_require(&rest[..end]); + if rest.starts_with(b"/**") && end > 4 { + end_of_jsdoc = at; } - at += end.max(1); } - count + count_import_or_require(&trivia[end_of_jsdoc..]) } /// `findImportOrRequire`, until there is no more. @@ -2610,9 +2902,18 @@ pub(crate) fn mode_for_usage_location( fn implied_node_format_for_emit( resolver: &Resolver, path: &[u8], + is_lib: bool, emit_module_kind: ModuleKind, ) -> ResolutionMode { let by_extension = format_by_extension(path); + // `parseTask.load`: `SourceFileMetaData{ImpliedNodeFormat: ResolutionModeCommonJS}` + if is_lib { + return if emit_module_kind.is_node() || by_extension == ResolutionMode::Require { + ResolutionMode::Require + } else { + ResolutionMode::None + }; + } if by_extension != ResolutionMode::None || !file_extension_is_one_of(path, &[b".ts", b".tsx", b".js", b".jsx"]) { @@ -2690,10 +2991,12 @@ fn get_resolution_diagnostic(options: &Options, extension: Extension, file: &Fil /// `resolveImportsAndModuleAugmentations`: with `importHelpers`, a file that can be emitted with /// helpers imports `tslib`. fn imports_helpers(options: &Options, hir: &File) -> bool { + // A JSON file is bound as a module, and has no `ExternalModuleIndicator`. + let is_external_module = hir.has_module_syntax && hir.kind != FileKind::Json; options.import_helpers && (hir.is_js || hir.kind != FileKind::Declaration - && (options.isolated_modules || hir.has_module_syntax)) + && (options.isolated_modules || is_external_module)) } /// `addRootFileTask`: the file that is read for the root file `root`, or else the error. @@ -2730,6 +3033,9 @@ struct Included<'a, 's> { roots_end: usize, /// Of each of those root files, its index in `roots`. root_of_start: &'a [u32], + /// The keys of `redirectAndFileFormat` that `createDiagnosticExplainingFile` has stored: a file + /// name for each path. + explained_in_diagnostics: std::cell::RefCell>>, } /// Where a problem with the inclusion of a file is reported, if that is in a file. @@ -2840,13 +3146,15 @@ impl Included<'_, '_> { if imports_helpers(options, hir) { specifiers.push((known::tslib, module.default_mode, 1395, 0, 0)); } - if (module.file_name().ends_with(b".tsx") || module.file_name().ends_with(b".jsx")) + if crate::resolve::is_jsx_file_name(module.file_name()) && let Some(runtime) = jsx_runtime_of(options, hir, atoms) { specifiers.push((atoms.intern(&runtime), module.default_mode, 1397, 0, 0)); } // `file.Imports()`: the specifiers of statements, then those of `import()`, the call and the type. let mut uses = hir.specifier_uses.to_vec(); + let visited = module_references(hir); + uses.retain(|u| is_among_imports(&visited, atoms, u)); uses.sort_by_key(|u| (u.kind.is_dynamic(), u.pos)); let calls = (uses.iter().any(|u| u.kind.is_call())).then(|| ExprsByKind::new(hir)); for u in &uses { @@ -3150,28 +3458,58 @@ impl Included<'_, '_> { problem = problem.with(2, code, &args); } } - // `explainRedirectAndImpliedFormat` let location = preferred_location.and_then(Visit::location); let Some(module) = self.modules.get(file.idx()) else { return (location, problem); }; let name = visits.first().map_or(module.path.pretty, |it| &it.name[..]); + for (code, args) in self.explain_redirect_and_implied_format(resolver, module, name, None) { + let args: Vec<&[u8]> = args.iter().map(Vec::as_slice).collect(); + problem = problem.with(1, code, &args); + } + (location, problem) + } + + /// `explainRedirectAndImpliedFormat` for the path of `name`, the name of `module` or of a + /// `redirectsFile` whose target is `module`: the code and the arguments of each message. + /// `to_relative_file_name`: `toFileName` of `ExplainFiles`, or else the caller is + /// `createDiagnosticExplainingFile`, which leaves a name as it is. The result for a path is + /// stored, so it has the names of whoever asks first. `ExplainFiles` asks last, and once. + fn explain_redirect_and_implied_format( + &self, + resolver: &Resolver, + module: &Module, + name: &[u8], + to_relative_file_name: Option>, + ) -> Vec<(u32, Vec>)> { + let is_case_sensitive = self.host.is_case_sensitive(); + let mut explained = self.explained_in_diagnostics.borrow_mut(); + let is_explained = (explained.iter()).any(|it| is_same_path(it, name, is_case_sensitive)); + let to_file_name: ToFileName<'_> = match to_relative_file_name { + Some(to_relative_file_name) if !is_explained => to_relative_file_name, + _ => &file_name_as_it_is, + }; + if to_relative_file_name.is_none() && !is_explained { + explained.push(name.to_vec()); + } + let mut result = Vec::new(); // `redirectFilesByPath` - let is_redirects_file = - !is_same_path(name, module.file_name(), self.host.is_case_sensitive()); + let is_redirects_file = !is_same_path(name, module.file_name(), is_case_sensitive); if !is_redirects_file && module.project_reference_source.is_some() { let source = self.atoms.bytes(module.project_reference_source); - problem = problem.with(1, 1428, &[&displayed_path(source)]); + result.push((1428, vec![to_file_name(source)])); } if is_redirects_file { - problem = problem.with(1, 1429, &[&displayed_path(module.file_name())]); - } else if let Some((code, args)) = - implied_format_reason(resolver, self.options, module, &file_name_as_it_is) - { - let args: Vec<&[u8]> = args.iter().map(Vec::as_slice).collect(); - problem = problem.with(1, code, &args); + result.push((1429, vec![to_file_name(module.file_name())])); + } else { + result.extend(implied_format_reason( + resolver, + self.options, + module, + to_file_name, + )); } - (location, problem) + result } /// `createDiagnosticExplainingFile` for the `processingDiagnostics` of the tasks that read no @@ -3389,8 +3727,9 @@ fn implied_format_reason( if !module.is_module() { return None; } - // `loadSourceFileMetaData` + // `loadSourceFileMetaData`, which `parseTask.load` does not call for a library. let scope = ancestors(dirname::(module.file_name())) + .filter(|_| !module.is_lib) .find_map(|dir| Some((resolver.package_json(dir)?, dir))) .map(|(json, dir)| (join(dir, b"package.json"), json)); let is_type_recorded = options.resolves_like_node @@ -3422,8 +3761,7 @@ pub(crate) fn source_file_may_be_emitted( module: &Module, is_case_sensitive: bool, ) -> bool { - if module.is_lib || module.hir.kind == FileKind::Declaration || module.is_from_external_library - { + if module.hir.kind == FileKind::Declaration || module.is_from_external_library { return false; } // The referenced project emits its own sources. @@ -3491,15 +3829,10 @@ pub fn declaration_emit_output_file_path( [remove_file_extension(&moved), extension].concat() } -/// `getOwnEmitOutputFilePath`, with `GetOutputExtension`. -pub fn own_emit_output_file_path( - options: &Options, - path: &[u8], - common: Option<&[u8]>, - is_case_sensitive: bool, -) -> Vec { +/// `GetOutputExtension` +pub fn get_output_extension(options: &Options, path: &[u8]) -> &'static [u8] { let is_one_of = |extensions: [&[u8]; 2]| file_extension_is_one_of(path, &extensions); - let extension: &[u8] = if file_extension_is_one_of(path, &[b".json"]) { + if file_extension_is_one_of(path, &[b".json"]) { b".json" } else if options.jsx == JsxEmit::Preserve && is_one_of([b".jsx", b".tsx"]) { b".jsx" @@ -3509,8 +3842,18 @@ pub fn own_emit_output_file_path( b".cjs" } else { b".js" - }; + } +} + +/// `getOwnEmitOutputFilePath` +pub fn own_emit_output_file_path( + options: &Options, + path: &[u8], + common: Option<&[u8]>, + is_case_sensitive: bool, +) -> Vec { let moved = source_file_path_in_new_dir(&options.out_dir, path, common, is_case_sensitive); + let extension = get_output_extension(options, path); [remove_file_extension(&moved), extension].concat() } @@ -3824,32 +4167,18 @@ impl<'s> Files<'s> { let of_file = file_path(path, is_case_sensitive, arena); let id = FileId(modules.len() as u32); let first = *by_path.files.entry(of_file.text).or_insert(id); - // Of the copies of a package file, the one that `collectFiles` comes to first is in the - // program. That is probably the one that is found first, so another one is only read - // if it turns out to be the one, or for what its resolutions log. - let (mut package, mut is_read) = (None, true); - if !options.retains_duplicate_packages - && let Some(package_id) = resolver.package_id(path) - { - let (index, is_first) = found.package(package_id); - is_read = is_first - || options.trace_resolution - || found.is_collecting && found.kept[index as usize].is_none(); - package = Some(index); - } modules.push(None); depths.push(u32::MAX); - // Another spelling of a name is only read if `collectFiles` comes to it first. - is_read &= first == id; if !is_case_sensitive { by_name.insert(path, id); } found.files.push(FoundFile { path: of_file, is_lib, - package, + package: None, first, - is_read, + // Another spelling of a name is only read if `collectFiles` comes to it first. + is_read: first == id, is_loaded: false, named: None, }); @@ -3903,6 +4232,17 @@ impl<'s> Files<'s> { } } without_file.append(&mut libs_without_file); + // `collectFiles`, `seen[data]`: of the tasks for one path only the first is walked, and + // the `processingDiagnostics` of the others are dropped. + let mut walked: Vec> = Vec::new(); + without_file.retain(|(visit, _)| { + let mut seen = walked.iter(); + let is_first = !seen.any(|name| is_same_path(name, &visit.name, is_case_sensitive)); + if is_first { + walked.push(visit.name.clone()); + } + is_first + }); let roots_end = starts.len(); // `addAutomaticTypeDirectiveTasks`: the last of `rootTasks`, for this file name. There is // one `parseTaskData` for a path, and `collectFiles` goes on from the first of its tasks: a @@ -3911,26 +4251,48 @@ impl<'s> Files<'s> { let is_containing_file = |found: &FoundFile| { is_same_path(found.path.pretty, &containing_file, is_case_sensitive) }; - let directives = if has_root_files && !all_found.files.iter().any(is_containing_file) { + let has_automatic_task = has_root_files && !all_found.files.iter().any(is_containing_file); + let directives = if has_automatic_task { automatic_type_directives(host, &resolver, options) } else { Vec::new() }; + // Its place in `taskDataByPath`: a sub task for the same file name gets it as `loadedTask`, + // so the file is not read. There is no such sub task unless the file exists. + let mut automatic_task = None; + if has_automatic_task && host.is_file(&containing_file) { + let task = add( + &containing_file, + false, + &mut modules, + &mut depths, + &mut all_found, + ); + // The last of `rootTasks` runs first. + all_found.files[task.idx()].is_read = false; + all_found.files[task.idx()].is_loaded = true; + depths[task.idx()] = 0; + automatic_task = Some(task); + } let automatic_tracer = options.trace_resolution.then(Tracer::default); // `subTasks` of that task. let mut automatic: Vec = Vec::new(); for name in &directives { - match resolver.resolve_type_reference( + match resolver.resolve_type_reference_and_id( name, &containing_file, ResolutionMode::None, automatic_tracer.as_ref(), ) { - Some((path, is_external)) => automatic.push(SubTask { - file: add(&path, false, &mut modules, &mut depths, &mut all_found), - increases_depth: is_external, - is_elided_on_depth: false, - }), + Some((path, is_external, package_id)) => { + let file = add(&path, false, &mut modules, &mut depths, &mut all_found); + automatic.push(SubTask { + file, + increases_depth: is_external, + is_elided_on_depth: false, + package: all_found.package_of_task(file, package_id), + }); + } // `*` matches whatever exists. None if name == b"*" => {} None => { @@ -3957,6 +4319,7 @@ impl<'s> Files<'s> { file, increases_depth: false, is_elided_on_depth: false, + package: None, }) .chain(automatic) .map(|task| (task, 0)) @@ -3966,6 +4329,21 @@ impl<'s> Files<'s> { // `subTasks` of one file. Reused for the next. let mut sub_tasks: Vec = Vec::new(); let mut package_json_info_cache = PackageJsonInfoCache::default(); + // `pathForLibFileResolutions`. The libraries of the options are resolved while `rootTasks` + // is made. + let mut lib_resolutions: Vec<(Vec, Vec)> = Vec::new(); + if options.trace_resolution && has_root_files { + for lib in &options.libs { + trace_path_for_lib_file( + host, + &resolver, + options, + lib_file_stem(lib), + &mut package_json_info_cache, + &mut lib_resolutions, + ); + } + } // The last of `rootTasks` runs first. let mut automatic_traces = automatic_tracer .map(Tracer::into_traces) @@ -4010,6 +4388,9 @@ impl<'s> Files<'s> { task.is_elided_on_depth && depth > options.max_node_module_js_depth }; let data = all_found.files[task.file.idx()].first; + // "Propagate packageId to data if we have one and data doesn't yet" + let package = &mut all_found.files[data.idx()].package; + *package = package.or(task.package); let depth = depth + u32::from(task.increases_depth); // "If we're seeing this task at a lower depth than before, reprocess its subtasks to // ensure they are loaded." A task starts them once. @@ -4083,19 +4464,23 @@ impl<'s> Files<'s> { let mut loaded = *loaded; let _linking = Spent::on(host, Phase::Link); sub_tasks.clear(); - for &(path, is_lib, increases_depth) in &loaded.references { + for &(path, is_lib, increases_depth, package_id) in &loaded.references { + let file = add(path, is_lib, &mut modules, &mut depths, &mut all_found); sub_tasks.push(SubTask { - file: add(path, is_lib, &mut modules, &mut depths, &mut all_found), + file, increases_depth, is_elided_on_depth: false, + package: all_found.package_of_task(file, package_id), }); } for &(start, end, path, code) in &loaded.unsupported_libs { // One task loads the file, whoever else refers to it. let file_name = displayed_path(path); let is_about_it = |message: &Problem| message.args[0] == *file_name; + let is_for_its_path = + |task: &Visit| is_same_path(&task.name, path, is_case_sensitive); if !unsupported.iter().any(|it| is_about_it(&it.3)) - && !without_file.iter().any(|it| is_about_it(&it.1)) + && !without_file.iter().any(|it| is_for_its_path(&it.0)) { let problem = reference_problem(options, code, path); unsupported.push((*id, start, end, problem)); @@ -4152,6 +4537,7 @@ impl<'s> Files<'s> { is_elided_on_depth: increases_depth && is_javascript_file(host, path) && strings::contains(path, b"/node_modules/"), + package: all_found.package_of_task(file, resolution.package_id), }); } edges.clear(); @@ -4162,9 +4548,28 @@ impl<'s> Files<'s> { if !is_lib { package_json_info_cache.load_source_file_meta_data(host, path); } - package_json_info_cache.get_package_json_infos(host, &mut loaded.traces); + let mut of_file = std::mem::take(&mut loaded.type_resolutions_trace); + package_json_info_cache.get_package_json_infos(host, &mut of_file); + for &(kind, value, ..) in &loaded.module.hir.references { + if kind == ReferenceKind::Lib + && !options.no_lib + && let Some(lib) = referenced_lib(host, options, atoms.bytes(value)) + { + trace_path_for_lib_file( + host, + &resolver, + options, + &lib, + &mut package_json_info_cache, + &mut lib_resolutions, + ); + } + } + let of_imports = &mut loaded.resolutions_trace; + package_json_info_cache.get_package_json_infos(host, of_imports); + of_file.append(of_imports); traces.resize_with(traces.len().max(id.idx() + 1), Vec::new); - traces[id.idx()] = std::mem::take(&mut loaded.traces); + traces[id.idx()] = of_file; } loaded.module.path = all_found.files[id.idx()].path; modules[id.idx()] = Some(loaded.module); @@ -4178,7 +4583,6 @@ impl<'s> Files<'s> { } // `collectFiles`, as far as it decides which copy of a package file is in the program and // logs. `declaration_order` puts the files in order. - all_found.is_collecting = true; seen.resize(modules.len(), false); traces.resize_with(modules.len(), Vec::new); loop { @@ -4186,8 +4590,11 @@ impl<'s> Files<'s> { Some(top) => { // Sub tasks that have not been started are not loaded. let has_started = !not_started.contains_key(&top.0); - let module = modules[top.0.idx()].as_ref().filter(|_| has_started); - let edges = module.map_or(&[][..], |it| it.edges); + let edges = match modules[top.0.idx()].as_ref().filter(|_| has_started) { + Some(module) => module.edges, + None if Some(top.0) == automatic_task => &starts[roots_end..], + None => &[], + }; let Some(&edge) = edges.get(top.1) else { stack.pop(); continue; @@ -4209,7 +4616,6 @@ impl<'s> Files<'s> { }; let FoundFile { path: Path { pretty: path, .. }, - mut package, first, .. } = all_found.files[file.idx()]; @@ -4229,16 +4635,10 @@ impl<'s> Files<'s> { if seen[file.idx()] { continue; } - // "Propagate packageId to data if we have one and data doesn't yet": the first task - // for the file may have none, a root file for one. - if package.is_none() - && !options.retains_duplicate_packages - && let Some(package_id) = resolver.package_id(path) + // `packageIdToSourceFile != nil && data.packageId.Name != ""` + if !options.retains_duplicate_packages + && let Some(package) = all_found.files[first.idx()].package { - package = Some(all_found.package(package_id).0); - all_found.files[file.idx()].package = package; - } - if let Some(package) = package { let kept = *all_found.kept[package as usize].get_or_insert(file); if kept != file { seen[file.idx()] = true; @@ -4248,7 +4648,9 @@ impl<'s> Files<'s> { continue; } } - if modules[file.idx()].is_none() { + if Some(file) == automatic_task { + log.append(&mut automatic_traces); + } else if modules[file.idx()].is_none() { // It is the one after all. The step is taken again when it has been read: its // task runs once more, as for the first time. match stack.last_mut() { @@ -4260,6 +4662,7 @@ impl<'s> Files<'s> { file, increases_depth: false, is_elided_on_depth: false, + package: None, }; queued.push((task, std::mem::replace(&mut depths[first.idx()], u32::MAX))); continue 'load; @@ -4270,6 +4673,10 @@ impl<'s> Files<'s> { } } drop(by_name); + // It is no file. + if let Some(task) = automatic_task { + seen[task.idx()] = false; + } for file in not_started.into_keys() { if let Some(module) = &mut modules[file.idx()] { module.edges = &[]; @@ -4309,14 +4716,16 @@ impl<'s> Files<'s> { modules.retain_mut(|module| { file += 1; if let Some(module) = module.as_mut().filter(|_| is_kept[file - 1]) { - // A task that is elided loads nothing. + // A task that is elided loads nothing. `collectFiles` goes on from the task for + // the automatic type directives to its sub tasks. edges.clear(); - edges.extend( - module - .edges - .iter() - .filter_map(|edge| renumbered[edge.idx()]), - ); + for edge in module.edges { + let tasks = match Some(*edge) == automatic_task { + true => &starts[roots_end..], + false => std::slice::from_ref(edge), + }; + edges.extend(tasks.iter().filter_map(|task| renumbered[task.idx()])); + } module.edges = slice_in(&edges, arena); (module.imports).retain(|_, target| match renumbered[target.idx()] { Some(new) => { @@ -4362,41 +4771,6 @@ impl<'s> Files<'s> { *start = renumber(*start); } } - // `pathForLibFileResolutions`, in the order of its keys. - let mut lib_traces = Vec::new(); - if options.trace_resolution && options.lib_replacement && has_root_files { - let mut libs: Vec> = (options.libs.iter()) - .map(|lib| lib_file_stem(lib).to_vec()) - .collect(); - for module in modules.iter().flatten().filter(|_| !options.no_lib) { - for &(kind, value, ..) in &module.hir.references { - if kind != ReferenceKind::Lib { - continue; - } - libs.extend(referenced_lib(host, options, atoms.bytes(value))); - } - } - let mut lookups: Vec<_> = (libs.iter()) - .filter(|lib| !lib.is_empty()) - .map(|lib| library_name_and_resolve_from(options, lib)) - .map(|(name, from)| { - let path = to_path(&from, host.is_case_sensitive()).into_owned(); - (path, name, from) - }) - .collect(); - lookups.sort(); - lookups.dedup(); - let tracer = Tracer::default(); - for (_, name, from) in &lookups { - resolver.resolve_module_name_traced( - name, - from, - ResolutionMode::Require, - Some(&tracer), - ); - } - lib_traces = tracer.into_traces(); - } for (module, &depth) in modules.iter_mut().flatten().zip(&depths) { module.is_from_external_library = depth > 0; } @@ -4453,8 +4827,9 @@ impl<'s> Files<'s> { for &(spec, mode, _, source) in &built { redirect(source, module.imports[&(spec, mode)]); } - let resolved_file_names = built.into_iter().map(|it| (it.0, it.1, it.3)); - module.redirected_imports = few(resolved_file_names.collect(), arena); + let mut redirected = module.redirected_imports.to_vec(); + redirected.extend(built.into_iter().map(|it| (it.0, it.1, it.3))); + module.redirected_imports = few(redirected, arena); module.unbuilt_imports = few(unbuilt, arena); } for (target, source) in redirected_from { @@ -4493,6 +4868,7 @@ impl<'s> Files<'s> { } } let mut package_jsons: FxHashMap<&'s [u8], Json> = FxHashMap::default(); + let mut previous_scope = Atom::NONE; for module in modules.iter().flatten() { let path: &'s [u8] = module.file_name(); if let Some((_, _, end)) = crate::resolve::node_module_path_parts(path) @@ -4501,6 +4877,15 @@ impl<'s> Files<'s> { { package_jsons.insert(&path[..end], json); } + let scope = module.package_json_directory; + if scope.is_some() && scope != std::mem::replace(&mut previous_scope, scope) { + let directory = atoms.bytes(scope); + if !package_jsons.contains_key(directory) + && let Some(json) = resolver.package_json(directory) + { + package_jsons.insert(slice_in(directory, arena), json); + } + } } let mut linked_directories: &'s [(&'s [u8], &'s [u8])] = &[]; let emitted = (modules.iter().flatten()) @@ -4643,6 +5028,7 @@ impl<'s> Files<'s> { libs_end, roots_end, root_of_start: &root_of_start, + explained_in_diagnostics: Default::default(), }; // None of their reasons is a reference in a file. let explained = included.explain_tasks_without_file(&without_file); @@ -4659,6 +5045,7 @@ impl<'s> Files<'s> { None => program_errors.push(problem), } } + let explained_in_diagnostics = included.explained_in_diagnostics.into_inner(); let has_type_only_stars = modules.iter().any(|m| { m.bound.export_stars.iter().any(|&(_, star)| { matches!( @@ -4717,6 +5104,7 @@ impl<'s> Files<'s> { modules_resolved_at_merge: &[], keeps_module_links: false, modules_with_nested_export_collisions: &[], + failed_lookups: &[], parents_in_other_files: map_in(arena), has_type_only_stars, @@ -4724,11 +5112,13 @@ impl<'s> Files<'s> { is_linked: false, no_module_links: ModuleSymbolLinks::empty_in(arena), is_merged: false, + has_symbols_to_combine: false, memo, order: &[], ranks: &[], components: Components::EMPTY, global_types: &[], + arrays_have_numeric_members: false, program_errors: session.keep(program_errors), include_errors: session.keep(include_errors), package_jsons, @@ -4740,13 +5130,17 @@ impl<'s> Files<'s> { roots_end, root_of_start: slice_in(&root_of_start, arena), package_copies: slice_in(&package_copies, arena), + explained_in_diagnostics: session.keep(explained_in_diagnostics), }; let merging = Spent::on(host, Phase::Merge); files.order = slice_in(&files.declaration_order(&starts), arena); if options.trace_resolution { - package_json_info_cache.get_package_json_infos(host, &mut lib_traces); let mut all = log; - all.extend(lib_traces); + all.extend( + lib_resolutions + .into_iter() + .flat_map(|resolution| resolution.1), + ); files.resolution_trace = session.keep(all); } let ranks = arena.alloc_slice_fill_copy(files.modules.len(), u32::MAX); @@ -4767,6 +5161,15 @@ impl<'s> Files<'s> { let known_names = (0..known::sym_iterator.0).map(Atom); files.global_types = arena.alloc_slice_fill_iter(known_names.map(|name| files.global_type(name))); + let begins_with_digit = |member: &(Atom, Sym)| { + let name = files.atoms.bytes(member.0); + name.first().is_some_and(u8::is_ascii_digit) + }; + let arrays_have_numeric_members = [known::Array, known::ReadonlyArray] + .into_iter() + .filter_map(|name| files.global_type_symbol(name)) + .any(|array| files.members_in_table(array).iter().any(begins_with_digit)); + files.arrays_have_numeric_members = arrays_have_numeric_members; files } @@ -4791,7 +5194,6 @@ impl<'s> Files<'s> { to_read: std::collections::VecDeque<(&'r [u8], bool)>, ready: Vec<((&'r [u8], bool), Cow<'static, [u8]>)>, seen: FxHashSet<&'r [u8]>, - seen_packages: FxHashSet>, /// Taken from `to_read` and not in `done` yet. in_progress: usize, done: FxHashMap<&'r [u8], Box>>, @@ -4800,7 +5202,6 @@ impl<'s> Files<'s> { seen: seeds.iter().map(|seed| seed.0).collect(), to_read: seeds.into(), ready: Vec::new(), - seen_packages: FxHashSet::default(), in_progress: 0, done: FxHashMap::default(), }); @@ -4834,10 +5235,10 @@ impl<'s> Files<'s> { arena, host, resolver, options, atoms, path, is_lib, text, )); // The sub tasks, except for whatever depends on a file's depth in packages. - let found = loaded + let found: Vec<(&'r [u8], bool)> = loaded .references .iter() - .map(|&(path, is_lib, _)| (path, is_lib)) + .map(|&(path, is_lib, ..)| (path, is_lib)) .chain( loaded .imports @@ -4849,17 +5250,12 @@ impl<'s> Files<'s> { && strings::contains(it.path, b"/node_modules/")) }) .map(|it| (it.path, false)), - ); - let found: Vec<(&'r [u8], bool, Option>)> = found - .map(|(path, is_lib)| (path, is_lib, resolver.package_id(path))) + ) .collect(); state = shared.lock(); let before = state.to_read.len(); - for (path, is_lib, package) in found { - if !state.seen.contains(path) - && package.is_none_or(|package| state.seen_packages.insert(package)) - { - state.seen.insert(path); + for (path, is_lib) in found { + if state.seen.insert(path) { state.to_read.push_back((path, is_lib)); } } @@ -5000,14 +5396,17 @@ impl<'s> Files<'s> { is_lib: bool, text: Cow<'static, [u8]>, ) -> Loaded<'s, 'r> { + // `parseTask.load`: a library is given `SourceFileMetaData{ImpliedNodeFormat: CommonJS}`, + // whatever `package.json` is above it. // `GetImpliedNodeFormatForFile`: a JSON file is neither kind of module, regardless of its // package. - let specifies_esm = !path.ends_with(b".json") + let specifies_esm = !is_lib + && !path.ends_with(b".json") && (options.resolves_like_node || strings::contains(path, b"/node_modules/")) && resolver.is_ecmascript_module(path); let is_esm = options.resolves_like_node && specifies_esm; let package_json_without_type = - if matches!(options.module, ModuleKind::Node16 | ModuleKind::Node18) { + if !is_lib && matches!(options.module, ModuleKind::Node16 | ModuleKind::Node18) { resolver .package_json_without_type(path) .map_or(Atom::NONE, |found| atoms.intern(&found)) @@ -5031,8 +5430,14 @@ impl<'s> Files<'s> { let options = resolver.options(); let mut referenced = of_program.referenced_options.iter(); let redirect_for_resolution = referenced.find(|&it| std::ptr::eq(it, options)); - let implied_format = implied_node_format_for_emit(program_resolver, path, options.module); + let implied_format = + implied_node_format_for_emit(program_resolver, path, is_lib, options.module); let default_mode = options.default_mode(implied_format); + let visited = match hir.specifier_uses.is_empty() { + true => Vec::new(), + false => module_references(&hir), + }; + let is_import = |u: &SpecifierUse| is_among_imports(&visited, atoms, u); let mut extensionless_imports = Vec::new(); // `moduleNames`, each with the mode it is resolved in, and whether it is a synthetic import // or one of `file.Imports()`: a module augmentation adds no file to the program. @@ -5045,7 +5450,7 @@ impl<'s> Files<'s> { let runtime = jsx_runtime_of(options, &hir, atoms); let runtime = runtime.map(|runtime| (atoms.intern(&runtime), runtime)); // Only a file that can contain JSX tags, according to its file name, imports their runtime. - let runtime = runtime.filter(|_| path.ends_with(b".tsx") || path.ends_with(b".jsx")); + let runtime = runtime.filter(|_| crate::resolve::is_jsx_file_name(path)); // Each entry of `moduleNames` is resolved, also one that repeats another. let (types_tracer, tracer) = (Tracer::default(), Tracer::default()); if of_program.trace_resolution { @@ -5060,17 +5465,11 @@ impl<'s> Files<'s> { if let Some((_, runtime)) = &runtime { trace(runtime, default_mode); } - // `collectModuleReferences` - let is_import = |u: &&SpecifierUse| { - bound.specifiers.contains(&u.spec) - || bound.ambient_specifiers.contains(&u.spec) - && !is_relative(atoms.bytes(u.spec)) - }; let statements = hir.specifier_uses.iter().filter(|u| !u.kind.is_dynamic()); let mut statements: Vec<&SpecifierUse> = statements.collect(); statements.sort_by_key(|u| u.pos); let uses = statements.into_iter().chain(dynamic_imports(&hir)); - for u in uses.filter(is_import) { + for u in uses.filter(|u| is_import(u)) { let mode = mode_for_usage_location(options, default_mode, u); trace(atoms.bytes(u.spec), mode); } @@ -5081,7 +5480,38 @@ impl<'s> Files<'s> { } } } + // `isExtensionlessRelativePathImport`, with the answer of `getSuggestedImportExtension`. + let extensionless_import = |spec: Atom| { + let text = atoms.bytes(spec); + if !options.resolves_like_node + || !path_is_relative(text) + || strings::contains_char(get_base_file_name(text), b'.') + { + return None; + } + let stem = join(dirname::(path), text); + let for_tsx: &'static [u8] = if options.jsx == JsxEmit::Preserve { + b".jsx" + } else { + b".js" + }; + let suggested = [ + (&b".mts"[..], &b".mjs"[..]), + (b".ts", b".js"), + (b".cts", b".cjs"), + (b".mjs", b".mjs"), + (b".js", b".js"), + (b".cjs", b".cjs"), + (b".tsx", for_tsx), + (b".jsx", b".jsx"), + (b".json", b".json"), + ] + .into_iter() + .find(|(e, _)| host.is_file(&[&stem[..], e].concat())); + Some((spec, suggested.map(|found| found.1))) + }; if let Some((spec, _)) = runtime { + extensionless_imports.extend(extensionless_import(spec)); module_names.push((spec, default_mode, true)); } // `file.Imports()`, then `file.ModuleAugmentations`: each with its place there. The @@ -5098,42 +5528,13 @@ impl<'s> Files<'s> { .chain(&bound.specifiers) .chain(bound.module_augmentations.iter()) { - let text = atoms.bytes(spec); - // `isExtensionlessRelativePathImport`. `HasExtension` uses `GetBaseFileName`, which - // ignores one trailing slash. - let base = text.strip_suffix(b"/").unwrap_or(text); - let base = &base[strings::last_index_of_char(base, b'/').map_or(0, |i| i + 1)..]; - if options.resolves_like_node - && (text.starts_with(b"./") || text.starts_with(b"../")) - && !strings::contains_char(base, b'.') - { - let stem = join(dirname::(path), text); - // `getSuggestedImportExtension` - let for_tsx: &[u8] = if options.jsx == JsxEmit::Preserve { - b".jsx" - } else { - b".js" - }; - let suggested = [ - (&b".mts"[..], &b".mjs"[..]), - (b".ts", b".js"), - (b".cts", b".cjs"), - (b".mjs", b".mjs"), - (b".js", b".js"), - (b".cjs", b".cjs"), - (b".tsx", for_tsx), - (b".jsx", b".jsx"), - (b".json", b".json"), - ] - .into_iter() - .find(|(e, _)| host.is_file(&[&stem[..], e].concat())); - extensionless_imports.push((spec, suggested.map(|found| found.1))); - } - // It is resolved in each mode that a use in the file requests. With each mode, where - // the first use in it is in `file.Imports()`. + extensionless_imports.extend(extensionless_import(spec)); + // It is resolved in each mode that one of `file.Imports()` requests. With each mode, + // where the first use in it is there. let mut modes = [(default_mode, AFTER_IMPORTS); 3]; let mut count = 0; - for u in hir.specifier_uses.iter().filter(|u| u.spec == spec) { + let uses = hir.specifier_uses.iter(); + for u in uses.filter(|u| u.spec == spec && is_import(u)) { let mode = mode_for_usage_location(options, default_mode, u); let place = (u.kind.is_dynamic(), u.pos); match modes[..count].iter_mut().find(|known| known.0 == mode) { @@ -5168,7 +5569,7 @@ impl<'s> Files<'s> { let (mut arbitrary_extension_imports, mut arbitrary_extension_files) = (Vec::new(), Vec::new()); let (mut ts_extension_imports, mut project_reference_imports) = (Vec::new(), Vec::new()); - let mut unbuilt_imports = Vec::new(); + let (mut unbuilt_imports, mut redirected_imports) = (Vec::new(), Vec::new()); for (spec, mode, is_import) in module_names { let text = atoms.bytes(spec); if text.is_empty() { @@ -5178,6 +5579,9 @@ impl<'s> Files<'s> { continue; }; let (key, found) = ((spec, mode), resolved.file_name); + if resolved.resolved_file_name != found { + redirected_imports.push((spec, mode, atoms.intern(resolved.resolved_file_name))); + } if let Some(id) = resolved.package_id { let package = (atoms.intern(id.name), found.ends_with(b".d.ts")); if !resolved_packages.contains(&package) { @@ -5208,7 +5612,7 @@ impl<'s> Files<'s> { Some(7042) => json_imports.push((spec, mode, atoms.intern(found))), Some(6263) => { arbitrary_extension_imports.push(key); - arbitrary_extension_files.push(atoms.intern(found)); + arbitrary_extension_files.push(atoms.intern(resolved.resolved_file_name)); } _ => {} } @@ -5238,6 +5642,7 @@ impl<'s> Files<'s> { should_add_file: should_add_file && redirect.is_none_or(|output| host.is_file(output)), increases_depth: resolved.is_external_library_import, + package_id: resolved.package_id.filter(|_| redirect.is_none()), is_importable: matches!(diagnostic, None | Some(6142)), unsupported_extension, }); @@ -5256,10 +5661,10 @@ impl<'s> Files<'s> { match referenced_file(host, of_program, &referenced_path(value, path), path) { Ok(found) => match of_program.parse_file_redirect(&found) { Some(output) if host.is_file(output) => { - references.push((resolver.keep(output), false, false)); + references.push((resolver.keep(output), false, false, None)); } Some(_) => {} - None => references.push((resolver.keep(&found), false, false)), + None => references.push((resolver.keep(&found), false, false, None)), }, Err(code) => missing_references.push((pos, code)), } @@ -5277,7 +5682,7 @@ impl<'s> Files<'s> { let end = pos + value.len() as u32; unsupported_libs.push((pos, end, found, code)); } - None => libs.push((found, true, false)), + None => libs.push((found, true, false, None)), } } None => missing_references.push((pos, 2726)), @@ -5290,14 +5695,14 @@ impl<'s> Files<'s> { } else { mode }; - match resolver.resolve_type_reference( + match resolver.resolve_type_reference_and_id( value, from, mode, of_program.trace_resolution.then_some(&types_tracer), ) { - Some((found, is_external)) => { - types.push((resolver.keep(&found), false, is_external)); + Some((found, is_external, package_id)) => { + types.push((resolver.keep(&found), false, is_external, package_id)); } None => missing_references.push((pos, 2688)), } @@ -5333,7 +5738,7 @@ impl<'s> Files<'s> { .package_json_directory(path) .map_or(Atom::NONE, |directory| atoms.intern(directory)), edges: &[], - redirected_imports: ArenaFew::default(), + redirected_imports: few(redirected_imports, arena), project_reference_imports: few(project_reference_imports, arena), unbuilt_imports: few(unbuilt_imports, arena), project_reference_source: Atom::NONE, @@ -5361,14 +5766,13 @@ impl<'s> Files<'s> { && module.bound.umd_globals.is_empty() // `make_module_clones`: it adds a symbol to the file of what it imports. && !(module.hir.imports.iter()).any(|import| import.namespace.is_some()); - let mut traces = types_tracer.into_traces(); - traces.extend(tracer.into_traces()); Loaded { module, imports, references, unsupported_libs, - traces, + type_resolutions_trace: types_tracer.into_traces(), + resolutions_trace: tracer.into_traces(), } } @@ -5393,7 +5797,7 @@ impl<'s> Files<'s> { pub fn jsx_runtime(&self, file: FileId) -> Option { let module = &self.modules[file.idx()]; // `resolveImportsAndModuleAugmentations`: only `ScriptKindTSX` and `ScriptKindJSX` import it. - if !module.file_name().ends_with(b".tsx") && !module.file_name().ends_with(b".jsx") { + if !crate::resolve::is_jsx_file_name(module.file_name()) { return None; } let runtime = jsx_runtime_of(self.options, &module.hir, &self.atoms)?; @@ -5519,13 +5923,6 @@ impl<'s> Files<'s> { } } for (name, sym) in additions { - // `mergeSymbol`: "Do not report an error when merging `var globalThis` with the built-in `globalThis`". Nothing else is - // done either. - if name == known::globalThis - && SymFlags::MODULE.intersects(get_excluded_symbol_flags(self.flags(sym))) - { - continue; - } // `mergeGlobalSymbol` let merged = match self.globals.get(name).copied() { Some(existing) => self.merge_symbol(existing, sym, false), @@ -5567,12 +5964,12 @@ impl<'s> Files<'s> { } let mut collected: Option> = None; for at in 0..self.modules[file].bound.ambient_modules.len() { - let (name, symbol, is_augmentation) = self.modules[file].bound.ambient_modules[at]; + let (name, symbol, is_global) = self.modules[file].bound.ambient_modules[at]; let sym = Sym { file: id, id: symbol, }; - if is_augmentation { + if !is_global { let module = &self.modules[file]; let collected = collected .get_or_insert_with(|| module_augmentations(&module.hir, &self.atoms)); @@ -5957,6 +6354,7 @@ impl<'s> Files<'s> { fn make_transient_symbols(&mut self) { for &file in self.order { let created = self.transient_symbols_of(file); + self.has_symbols_to_combine |= created.iter().any(|it| it.0.is_combined); add_transient_symbols(&mut self.modules[file.idx()], created); } } @@ -6006,7 +6404,7 @@ impl<'s> Files<'s> { if merged.file == parent.file { self.parents_in_other_files.remove(&merged); self.symbol_mut(merged).parent = parent.id; - } else if self.parent_of_symbol(merged) != Some(parent) { + } else { self.parents_in_other_files.insert(merged, parent); } } @@ -6462,6 +6860,20 @@ impl<'s> Files<'s> { } } + /// `moduleSymbol.ValueDeclaration.Locals()[name]`: a local declaration of the file, or of the + /// first `declare module "m"`. + pub fn local_of_module(&self, module: Sym, name: Atom) -> Option { + let &(of, decl) = self.decls_of(module).first()?; + let bound = self.bound(of); + let scope = match decl { + Decl::File => 0, + Decl::Module(m) => bound.module_scope[m.idx()].idx(), + _ => return None, + }; + let local = bound.lookup(bound.scopes.get(scope)?.locals, name)?; + Some(self.sym(of, local)) + } + /// `symbol.ValueDeclaration` #[inline] pub fn value_declaration(&self, sym: Sym) -> Option<(FileId, Decl)> { @@ -6642,12 +7054,14 @@ impl<'s> Files<'s> { /// `getParentOfSymbol` pub fn parent_of_symbol(&self, sym: Sym) -> Option { - if !self.parents_in_other_files.is_empty() + let symbol = self.symbol(sym); + // `mergeSymbolTable` sets the parent of a transient symbol only. + if symbol.flags.contains(SymFlags::TRANSIENT) && let Some(&parent) = self.parents_in_other_files.get(&sym) { return Some(self.canonical(parent)); } - let parent = self.symbol(sym).parent; + let parent = symbol.parent; parent.is_some().then(|| self.sym(sym.file, parent)) } @@ -6794,24 +7208,7 @@ impl<'s> Files<'s> { _ => meaning & SymFlags::MODULE_MEMBER, }; let container = self.sym(file, s.symbol); - // `IsSourceFile(location) || IsModuleDeclaration(location) && - // location.Flags&NodeFlagsAmbient != 0 && !IsGlobalScopeAugmentation(location)` - let is_external_module = || match s.kind { - ScopeKind::File => true, - ScopeKind::Module(m) => { - let hir = self.hir(file); - let mut around = std::iter::successors(Some(scope), |&at| { - Some(bound.scopes[at.idx()].parent).filter(|parent| parent.is_some()) - }); - !matches!(hir[m].name, ModuleName::Global) - && (hir.kind == FileKind::Declaration - || around.any(|at| { - matches!(bound.scopes[at.idx()].kind, ScopeKind::Module(it) - if hir[it].flags.contains(Flags::AMBIENT)) - })) - } - _ => false, - }; + let is_external_module = || bound.is_external_module(self.hir(file), scope); // "First see if the module has an export default and if the local name of that export default matches." if let Some(default) = self.export(container, known::default) && self.flags(default).intersects(meaning) @@ -6836,6 +7233,21 @@ impl<'s> Files<'s> { return Ok(Some(sym)); } } + // The name of a method or an accessor is a child of it: its locals are searched. From + // there `useResult` is false for a type and for a function scoped variable. + if let ScopeKind::FunctionName(f) = s.kind { + let function = bound.fns[f.idx()].scope; + let locals = bound.scopes[function.idx()].locals; + let held = bound.lookup(locals, name).map(|id| self.sym(file, id)); + if let Some(sym) = lookup(SymbolTable::Locals(file, function), held, meaning) { + let flags = self.flags(sym); + let is_function_scoped = (meaning & flags).intersects(SymFlags::VARIABLE) + && flags.intersects(SymFlags::FUNCTION_SCOPED_VARIABLE); + if !(meaning & flags).intersects(SymFlags::TYPE) && !is_function_scoped { + return Ok(Some(sym)); + } + } + } from = s.kind; scope = s.parent; } @@ -6923,6 +7335,13 @@ impl<'s> Files<'s> { } } + /// `tryFindAmbientModule(moduleName, true /*withAugmentations*/)`: a relative name never + /// matches. + pub fn try_find_ambient_module(&self, spec: Atom) -> Option { + let &ambient = self.ambient_modules.get(&spec)?; + (!is_relative(self.atoms.bytes(spec))).then(|| self.canonical(ambient)) + } + /// `resolveExternalModule`: the module that `spec` resolves to in `file` in `mode`. pub fn module_of_specifier_as( &self, @@ -6934,11 +7353,8 @@ impl<'s> Files<'s> { if spec.is_none() { return None; } - // `tryFindAmbientModule`: a relative name never matches. - if let Some(&ambient) = self.ambient_modules.get(&spec) - && !is_relative(self.atoms.bytes(spec)) - { - return Some(self.canonical(ambient)); + if let Some(ambient) = self.try_find_ambient_module(spec) { + return Some(ambient); } // A file that is not a module ends the search anyway. if let Some(&target) = self.module(file).imports.get(&(spec, mode)) { @@ -7064,12 +7480,39 @@ impl<'s> Files<'s> { pub fn is_only_importable_as_default(&self, usage: impl Usage, module: Sym) -> bool { self.options.module.is_node() && usage.mode(self) == ResolutionMode::Import - && self - .symbol(module) - .decls - .iter() - .any(|d| matches!(d, Decl::File)) - && self.is_json_module(module.file) + && (self.source_file_of_module(module)).is_some_and(|file| self.is_json_module(file)) + } + + /// `GetSourceFileOfModule` + fn source_file_of_module(&self, module: Sym) -> Option { + let declaration = self.value_declaration(module).or_else(|| { + // `GetNonAugmentationDeclaration` + let is_augmentation = |&(file, decl): &(FileId, Decl)| { + matches!(decl, Decl::Module(m) if self.hir(file)[m].name == ModuleName::Global + || self.is_external_module_augmentation(file, m)) + }; + (self.decls_of(module).iter()) + .find(|&it| !is_augmentation(it)) + .copied() + }); + declaration.map(|(file, _)| file) + } + + /// `IsExternalModuleAugmentation` + pub fn is_external_module_augmentation(&self, file: FileId, m: ModuleId) -> bool { + let (hir, bound) = (self.hir(file), self.bound(file)); + let is_ambient_module = |it: ModuleId| !matches!(hir[it].name, ModuleName::Ident(_)); + let parent = |it: ModuleId| bound.stmt_parent.get(hir[it].stmt.idx()); + is_ambient_module(m) + && match parent(m) { + Some(bind::Parent::File) => hir.has_module_syntax, + Some(&bind::Parent::Module(around)) => { + is_ambient_module(around) + && matches!(parent(around), Some(bind::Parent::File)) + && !hir.has_module_syntax + } + _ => false, + } } /// `ast.IsJsonSourceFile(file) || tspath.GetDeclarationFileExtension(file.FileName()) == @@ -7153,6 +7596,7 @@ impl<'s> Files<'s> { Some((module, links)) }); let mut nested: Vec = at_merge.filter(is_nested).map(|it| *it.0).collect(); + let mut failed_lookups: Vec = Vec::new(); for tasks in &steps { let resolved: Vec> = tasks .iter() @@ -7162,12 +7606,15 @@ impl<'s> Files<'s> { *resolved[at].lock() = self.resolve_files(&tasks[at]); }); for resolved in &resolved { - let resolved = std::mem::take(&mut *resolved.lock()); + let mut resolved = std::mem::take(&mut *resolved.lock()); let links = resolved.module_links.iter(); nested.extend(links.filter(is_nested).map(|it| *it.0)); + failed_lookups.append(&mut resolved.failed_lookups); self.publish(resolved); } } + failed_lookups.sort_by_key(|it| (it.file, it.identifier)); + self.failed_lookups = slice_in(&failed_lookups, self.arena); nested.retain(|&module| self.canonical(module) == module); nested.sort_unstable(); nested.dedup(); @@ -7194,9 +7641,19 @@ impl<'s> Files<'s> { }) }; for sym in files.clone().flat_map(symbols) { - if self.flags(sym).contains(SymFlags::ALIAS) { - resolver.alias_links(sym); + if !self.flags(sym).contains(SymFlags::ALIAS) { + continue; } + // Where the walk comes to an `ExportAssignment`, which declares one of these names. + let symbol = self.symbol(sym); + if symbol.name == known::default || symbol.name == known::export_equals { + for &decl in &symbol.decls { + if let Decl::ExportExpr(stmt) = decl { + resolver.check_export_assignment(sym.file, stmt); + } + } + } + resolver.alias_links(sym); } let mut decls = Vec::new(); let mut of_symbol = Vec::new(); @@ -7240,6 +7697,14 @@ impl<'s> Files<'s> { } } + /// The `FailedLookup`s for the identifier `e` of `file`. + pub fn failed_lookups_of(&self, file: FileId, e: ExprId) -> &'s [FailedLookup<'s>] { + let all = self.failed_lookups; + let from = all.partition_point(|it| (it.file, it.identifier) < (file, e)); + let count = all[from..].partition_point(|it| (it.file, it.identifier) == (file, e)); + &all[from..from + count] + } + /// `means(sym, meaning)`, if no alias has to be resolved for it. #[inline] fn has_meaning_by_own_flags(&self, sym: Sym, meaning: SymFlags) -> Option { @@ -7445,6 +7910,26 @@ impl<'s> Files<'s> { self.transient_symbol_of_alias(alias, true) } + /// Whether `alias`, or an alias on the chain to its target, has a `combined_symbol`: only the + /// types tell what `resolveAlias` and `getSymbolFlags` give for it. + pub fn has_symbol_to_combine(&self, mut alias: Sym) -> bool { + let mut links_followed = 0; + while self.has_symbols_to_combine + && links_followed < 32 + && self.flags(alias).contains(SymFlags::ALIAS) + { + if self.combined_symbol(alias).is_some() { + return true; + } + let Some(next) = self.alias_links(alias).immediate_target else { + return false; + }; + alias = next; + links_followed += 1; + } + false + } + /// `exportTypeLinks.target` of a symbol that `cloneTypeAsModuleType` created. pub fn target_of_module_clone(&self, symbol: Sym) -> Option { let created = self.transient_symbol(symbol)?; @@ -7598,6 +8083,7 @@ impl<'a, 's> AliasResolver<'a, 's> { buffer: buffer.map(std::cell::RefCell::new), arena: Default::default(), members_resolved: Default::default(), + resolved_symbols: Default::default(), } } } @@ -7732,6 +8218,31 @@ impl<'s> Resolve<'s> for AliasResolver<'_, 's> { fn set_members_resolved(&self, symbol: Sym) -> bool { self.members_resolved.borrow_mut().insert(symbol) } + + fn is_alias_in_progress(&self, sym: Sym) -> bool { + self.in_flight.borrow().iter().any(|begun| begun.0 == sym) + } + + fn has_resolved_symbol(&self, file: FileId, e: ExprId) -> bool { + self.resolved_symbols.borrow().contains(&(file, e)) + } + + fn set_resolved_symbol(&self, file: FileId, e: ExprId) { + self.resolved_symbols.borrow_mut().insert((file, e)); + } + + /// Only the link step keeps them. + fn note_failed_lookup(&self, file: FileId, e: ExprId) { + if let Some(buffer) = &self.buffer { + let in_flight = self.in_flight.borrow(); + let in_progress: SmallVec<[Sym; 4]> = in_flight.iter().map(|begun| begun.0).collect(); + buffer.borrow_mut().failed_lookups.push(FailedLookup { + file, + identifier: e, + aliases_in_progress: slice_in(&in_progress, self.arena()), + }); + } + } } /// The public methods of `Files` that resolve aliases: the methods of `Resolve` of the same names. diff --git a/src/sema/program/explain_files.rs b/src/sema/program/explain_files.rs index 7ffae280bf5c..b183256203ba 100644 --- a/src/sema/program/explain_files.rs +++ b/src/sema/program/explain_files.rs @@ -1,19 +1,23 @@ //! `Program.ExplainFiles`: what `explainFiles` prints. -use super::{ - FileId, Files, IncludeReason, Included, Module, Reference, Visit, implied_format_reason, -}; +use super::{FileId, Files, IncludeReason, Included, Module, Reference, Visit}; use crate::messages; use crate::resolve::{Host, Resolver}; use crate::session::Session; impl Files<'_> { - /// The lines. `to_relative_file_name`: `toRelativeFileName`. + /// The lines. `has_made_diagnostics`: `includeProcessor.getDiagnostics` has been called. + /// `to_relative_file_name`: `toRelativeFileName`. pub fn explain_files( &self, host: &dyn Host, + has_made_diagnostics: bool, to_relative_file_name: &dyn Fn(&[u8]) -> Vec, ) -> Vec> { + let explained_in_diagnostics = match has_made_diagnostics { + true => self.explained_in_diagnostics.to_vec(), + false => Vec::new(), + }; let included = Included { host, options: self.options, @@ -25,6 +29,7 @@ impl Files<'_> { libs_end: self.libs_end, roots_end: self.roots_end, root_of_start: self.root_of_start, + explained_in_diagnostics: explained_in_diagnostics.into(), }; let resolving = Session::new(); let resolver = Resolver::new(&resolving, host, self.options); @@ -51,8 +56,8 @@ impl Files<'_> { Some(text.get(it.start as usize..it.end as usize)?.to_vec()) }; let mut lines: Vec> = Vec::new(); - // `is_redirect`: `name` is that of a `redirectsFile`, and `file` is its target. - let mut explain_file = |name: &[u8], file: FileId, is_redirect: bool| { + // `name` is that of `file`, or of a `redirectsFile` whose target is `file`. + let mut explain_file = |name: &[u8], file: FileId| { let module: &Module = &self.modules[file.idx()]; lines.push(to_relative_file_name(name)); for visit in reasons_of(file, name) { @@ -64,19 +69,10 @@ impl Files<'_> { } lines.push(line(code, &args)); } - // `explainRedirectAndImpliedFormat` - let options = self.options; - if !is_redirect && module.project_reference_source.is_some() { - let source = self.atoms.bytes(module.project_reference_source); - lines.push(line(1428, &[to_relative_file_name(source)])); - } - if is_redirect { - lines.push(line(1429, &[to_relative_file_name(module.file_name())])); - } else if let Some((code, args)) = - implied_format_reason(&resolver, options, module, to_relative_file_name) - { - lines.push(line(code, &args)); - } + let to_file_name = Some(to_relative_file_name); + let explained = + included.explain_redirect_and_implied_format(&resolver, module, name, to_file_name); + lines.extend(explained.iter().map(|(code, args)| line(*code, args))); }; // The visit at which `collectFiles` goes on to what the file refers to. let first: Vec> = (self.modules.iter().enumerate()) @@ -112,14 +108,14 @@ impl Files<'_> { while files_explained < index && let Some(&file) = source_files.next() { - explain_file(self.modules[file.idx()].file_name(), file, false); + explain_file(self.modules[file.idx()].file_name(), file); files_explained += 1; } - explain_file(name, target, true); + explain_file(name, target); files_explained += 1; } for &file in source_files { - explain_file(self.modules[file.idx()].file_name(), file, false); + explain_file(self.modules[file.idx()].file_name(), file); } lines } diff --git a/src/sema/resolve.rs b/src/sema/resolve.rs index bcdc41104751..adfa2a474b08 100644 --- a/src/sema/resolve.rs +++ b/src/sema/resolve.rs @@ -4,7 +4,7 @@ use crate::hir::ResolutionMode; use crate::json::Json; use crate::session::{Arena, Session}; -use crate::util::ShardedMap; +use crate::util::{FxHashSet, ShardedMap}; use bstr::ByteSlice; use bun_core::strings; use bun_paths::fs::Path; @@ -130,7 +130,8 @@ pub trait Host: Sync { /// `None`: an error, after which typescript-go goes on as if the file had no fields. /// An `Expected[T]` that is `Valid` is its `Value`. One that is not is a value of its /// `ActualJSONType` that is no `T`: for a `map[string]string` and an object, `Value` with a - /// name repeated at the end. One that is `Null` has a `null` too, behind its other value. + /// name repeated at the end. One that is `Null` has a `null` too, behind its other value. Last + /// comes the `Value` of a `map[string]string` that is not `Valid` and no object. /// What the parser leaves in `arena`, which belongs to the calling thread, is garbage. fn parse_package_json(&self, arena: &crate::session::Arena, text: &[u8]) -> Option; /// Calls `work` with every index below `count`, on any number of threads. @@ -365,6 +366,14 @@ impl ScriptKind { } } +/// Whether `GetScriptKindFromFileName` is `ScriptKindTSX` or `ScriptKindJSX`. +pub fn is_jsx_file_name(path: &[u8]) -> bool { + strings::last_index_of_char(path, b'.').is_some_and(|dot| { + let extension = &path[dot..]; + extension.eq_ignore_ascii_case(b".tsx") || extension.eq_ignore_ascii_case(b".jsx") + }) +} + /// The LANGUAGE of a file: `is_javascript`, unless the host knows better than the name. What goes /// by the NAME of a file asks `is_javascript`: which files `include` finds, and which files are /// tried for `./a.js`. @@ -422,9 +431,9 @@ pub struct Options { /// `customConditions`: conditions that match in the `exports` and `imports` of a /// `package.json`, in addition to the default ones. pub custom_conditions: Vec>, - /// `getNodeResolutionFeatures`: the `exports` and the `imports` of a `package.json` are - /// honored. Only bundler resolution can disable this. + /// `GetResolvePackageJsonExports`. The resolver asks `has_exports_feature`. pub resolve_package_json_exports: bool, + /// `GetResolvePackageJsonImports`. The resolver asks `has_imports_feature`. pub resolve_package_json_imports: bool, /// `rootDirs`, as absolute paths: directories that are treated as one directory when a relative /// specifier is resolved. @@ -619,6 +628,17 @@ impl Options { .collect() } + /// `NodeResolutionFeaturesExports` in `newResolutionState`: the `exports` of a `package.json` + /// are honored. Only bundler resolution asks the option (`getNodeResolutionFeatures`). + fn has_exports_feature(&self) -> bool { + self.resolves_like_node || self.resolve_package_json_exports + } + + /// `NodeResolutionFeaturesImports`, likewise. + fn has_imports_feature(&self) -> bool { + self.resolves_like_node || self.resolve_package_json_imports + } + /// `importSyntaxAffectsModuleResolution` pub fn import_syntax_affects_module_resolution(&self) -> bool { self.resolves_like_node @@ -826,9 +846,9 @@ impl Options { resolution.as_deref(), Some(b"node16" | b"nodenext" | b"bundler") ); - // `getNodeResolutionFeatures` let like_node = options.resolves_like_node; - let is_not_off = |name: &[u8]| like_node || specified(name) != Some(false); + // `IsTrueOrUnknown` + let is_not_off = |name: &[u8]| specified(name) != Some(false); options.resolve_package_json_exports = is_not_off(b"resolvePackageJsonExports"); options.resolve_package_json_imports = is_not_off(b"resolvePackageJsonImports"); // `GetResolveJsonModule` @@ -1045,7 +1065,7 @@ pub fn to_file_name_lower_case(file_name: &[u8]) -> Vec { } let mut out = Vec::with_capacity(file_name.len()); for c in file_name.chars() { - let lower = c.to_lowercase().filter(|_| c != '\u{130}'); + let lower = to_lowercase_unicode_15(c).filter(|_| c != '\u{130}'); for c in lower.chain((c == '\u{130}').then_some(c)) { out.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()); } @@ -1194,7 +1214,7 @@ pub fn displayed_path(path: &[u8]) -> Cow<'_, [u8]> { } /// `GetPathComponents(path, "")`, after `normalize_slashes`: the root, then the names. -fn get_path_components(path: &[u8]) -> SmallVec<[&[u8]; 8]> { +pub(crate) fn get_path_components(path: &[u8]) -> SmallVec<[&[u8]; 8]> { let (root, rest) = path.split_at(get_root_length(path)); let mut components: SmallVec<[&[u8]; 8]> = smallvec![root]; components.extend(strings::split(rest, b"/")); @@ -1217,7 +1237,7 @@ fn normalized_for_lookup(path: &[u8]) -> Option> { } /// `NormalizePath` of an absolute path, which keeps a separator at the end. -fn normalize_path(path: Vec) -> Vec { +pub(crate) fn normalize_path(path: Vec) -> Vec { let Some(mut normalized) = normalized_for_lookup(strings::without_trailing_slash(&path)) else { return path; }; @@ -1609,6 +1629,9 @@ impl PackageId<'_> { #[derive(Copy, Clone, Debug)] pub struct ResolvedModule<'h> { /// `ResolvedFileName`. For a declaration file of a referenced project, the source it is emitted from. + /// It is not normalized if it was found in a type root. + pub resolved_file_name: &'h [u8], + /// `parseTask.normalizedFilePath` of the task for it: its name in the program. pub file_name: &'h [u8], pub using_ts_extension: bool, /// `Extension` is one that requires `allowArbitraryExtensions` (`GetResolutionDiagnostic`). @@ -1635,9 +1658,6 @@ pub struct Resolver<'h> { /// Cache of the results of `resolve_module_name`. The key is the directory, `//`, the mode as a /// digit, and the specifier. No directory contains `//`. resolved: ShardedMap<&'h [u8], Option>>, - /// `parseTaskData.packageId`, by the `tspath.Path` of `ResolvedFileName`: the first id that a - /// resolution to the file has. - package_ids: ShardedMap<&'h [u8], PackageId<'h>>, /// `resolutionState.diagnostics` of all lookups: whether it concerns `imports`, the entry, and /// the `package.json`. ambiguous_roots: bun_threading::Guarded>, @@ -1655,18 +1675,24 @@ pub struct Resolver<'h> { /// `guessDirectorySymlink`: the real path of the symlinked directory and the path of the symlink, /// inferred from a file at `real` that was found at `link`. -fn guess_directory_link(real: &[u8], link: &[u8]) -> Option<(Vec, Vec)> { +fn guess_directory_link( + real: &[u8], + link: &[u8], + is_case_sensitive: bool, +) -> Option<(Vec, Vec)> { let mut a: Vec<&[u8]> = strings::split(real, b"/").collect(); let mut b: Vec<&[u8]> = strings::split(link, b"/").collect(); // `isNodeModulesOrScopedPackageDirectory`: the symlink is an entry of such a directory, not the // directory itself. - let holds_packages = |name: &[u8]| name == b"node_modules" || name.starts_with(b"@"); + let holds_packages = |name: &[u8]| { + is_same_path(name, b"node_modules", is_case_sensitive) || name.starts_with(b"@") + }; let mut is_directory = false; while a.len() >= 2 && b.len() >= 2 && !holds_packages(a[a.len() - 2]) && !holds_packages(b[b.len() - 2]) - && a[a.len() - 1] == b[b.len() - 1] + && is_same_path(a[a.len() - 1], b[b.len() - 1], is_case_sensitive) { a.pop(); b.pop(); @@ -1675,6 +1701,40 @@ fn guess_directory_link(real: &[u8], link: &[u8]) -> Option<(Vec, Vec)> is_directory.then(|| (a.join(&b"/"[..]), b.join(&b"/"[..]))) } +/// `symlinks.KnownSymlinks` +struct KnownSymlinks { + /// The keys of `directories`, without the separator at the end. + directories: FxHashSet>, + /// `directoriesByRealpath`: `Real` of each directory, with a symlink to it. + directories_by_realpath: Vec<(Vec, Vec)>, + is_case_sensitive: bool, +} + +impl KnownSymlinks { + /// `HasDirectory` + fn has_directory(&self, symlink: &[u8]) -> bool { + self.directories + .contains(&*to_path(symlink, self.is_case_sensitive)) + } + + /// `ProcessResolution`, `SetDirectory`. Both paths are absolute and normalized. + fn process_resolution(&mut self, original_path: &[u8], resolved_file_name: &[u8]) { + let is_case_sensitive = self.is_case_sensitive; + let Some(pair) = guess_directory_link(resolved_file_name, original_path, is_case_sensitive) + else { + return; + }; + let symlink_path = to_path(&pair.1, is_case_sensitive).into_owned(); + // `ContainsIgnoredPath` + let is_ignored = [b"/node_modules/.".as_slice(), b"/.git", b".#"] + .iter() + .any(|ignored| strings::contains(&symlink_path, ignored)); + if !is_ignored && self.directories.insert(symlink_path) { + self.directories_by_realpath.push(pair); + } + } +} + /// `GetRelativePathFromDirectory` for two absolute, normalized paths. The result is text: a `to` /// with another root is `displayed_path`. pub fn get_relative_path_from_directory( @@ -1914,7 +1974,6 @@ impl<'h> Resolver<'h> { dirs: ShardedMap::default(), files: ShardedMap::default(), resolved: ShardedMap::default(), - package_ids: ShardedMap::default(), ambiguous_roots: bun_threading::Guarded::new(Vec::new_in(session)), links: bun_threading::Guarded::new(Vec::new_in(session)), linked_packages: ShardedMap::default(), @@ -2031,17 +2090,10 @@ impl<'h> Resolver<'h> { &self, emitted: impl Iterator, ) -> Vec<(Vec, Vec)> { - let mut found: Vec<(Vec, Vec)> = Vec::new(); - // `processResolution`, `SetDirectory` - let mut note = |real: &[u8], link: &[u8]| { - if let Some(pair) = guess_directory_link(real, link) - && ![b"/node_modules/.".as_slice(), b"/.git", b".#"] - .iter() - .any(|ignored| strings::contains(&pair.1, ignored)) - && !found.iter().any(|known| known.1 == pair.1) - { - found.push(pair); - } + let mut known_symlinks = KnownSymlinks { + directories: FxHashSet::default(), + directories_by_realpath: Vec::new(), + is_case_sensitive: self.host.is_case_sensitive(), }; // The imports of a file of a referenced project are resolved by the resolver of that project. let mut links: Vec<(&[u8], &[u8])> = self.links.lock().to_vec(); @@ -2051,7 +2103,7 @@ impl<'h> Resolver<'h> { links.sort(); links.dedup(); for (link, real) in &links { - note(real, &join(b"/", link)); + known_symlinks.process_resolution(&join(b"/", link), real); } let mut not_linked: Vec> = Vec::new(); let mut seen: Vec<&[u8]> = Vec::new(); @@ -2063,21 +2115,30 @@ impl<'h> Resolver<'h> { continue; } seen.push(directory); + let node_modules = inside(directory, b"node_modules"); // `GetRuntimeDependencyNames` for field in [ b"dependencies".as_slice(), b"peerDependencies", b"optionalDependencies", ] { - let Some(Json::Object(entries)) = package.json.get(field) else { - continue; - }; - for (name, _) in entries { + for (name, _) in get_map_value(&package.json, field) { + // A link to the package or to its types, next to the `package.json`. + let types_package_name = [b"@types/", &mangle_scoped(name)[..]].concat(); + if known_symlinks.has_directory(&join(&node_modules, name)) + || !name.starts_with(b"@types") + && known_symlinks + .has_directory(&join(&node_modules, &types_package_name)) + { + continue; + } match self.resolve_package_directory(name, directory) { - Some((Some(original_path), resolved_file_name)) => note( - &inside(&resolved_file_name, b"package.json"), - &inside(&original_path, b"package.json"), - ), + Some((Some(original_path), resolved_file_name)) => { + known_symlinks.process_resolution( + &inside(&original_path, b"package.json"), + &inside(&resolved_file_name, b"package.json"), + ); + } Some((None, resolved_file_name)) => { if !not_linked.contains(&resolved_file_name) { not_linked.push(resolved_file_name); @@ -2093,11 +2154,12 @@ impl<'h> Resolver<'h> { // is none. Of several, the order of a Go map decides which is first, and each one is more // likely not to be. if let [resolved_file_name] = ¬_linked[..] { - note( - &inside(resolved_file_name, b"package.json"), + known_symlinks.process_resolution( &inside(&self.options.current_directory, b"package.json"), + &inside(resolved_file_name, b"package.json"), ); } + let mut found = known_symlinks.directories_by_realpath; found.sort(); found } @@ -2245,11 +2307,15 @@ impl<'h> Resolver<'h> { // would first bring it up to date with the source. let source = self.source_of_project_reference_redirect(&path); let is_project_reference_redirect = source.is_some(); + let resolved_file_name = self.keep(&source.unwrap_or(path)); // `parseTask.addSubTask`: the program has a file under its normalized name. - let file_name = self.keep(&source.unwrap_or_else(|| normalize_path(path))); - self.propagate_package_id(file_name, package_id); + let file_name = match normalized_for_lookup(resolved_file_name) { + Some(normalized) => self.keep(&normalized), + None => resolved_file_name, + }; ResolvedModule { is_project_reference_redirect, + resolved_file_name, file_name, using_ts_extension: outcome.using_ts_extension.get(), has_arbitrary_extension: outcome.arbitrary_extension.get(), @@ -2306,18 +2372,6 @@ impl<'h> Resolver<'h> { }) } - /// `filesParser.start`: "Propagate packageId to data if we have one and data doesn't yet". - fn propagate_package_id(&self, file_name: &[u8], package_id: Option>) { - let Some(package_id) = package_id else { - return; - }; - let mut buffer = path_buffer_pool::get(); - let path = to_path_in(file_name, self.host.is_case_sensitive(), &mut buffer[..]); - if self.package_ids.get_ref(&*path).is_none() { - self.package_ids.insert_ref(self.keep(&path), package_id); - } - } - /// `resolveNodeLike`: `ResolvedFileName` and `AlternateResult`. fn resolve_node_like( &self, @@ -2350,7 +2404,7 @@ impl<'h> Resolver<'h> { }; if !(look.outcome.found_package.get() && !look.is_config_lookup - && self.options.resolve_package_json_exports + && self.options.has_exports_feature() && !look.ignores_exports && (look.typescript || look.declarations) && !is_relative(spec) @@ -2427,7 +2481,7 @@ impl<'h> Resolver<'h> { } // Tries each location in turn until one produces a result. let mut found = Found::No; - if self.options.resolve_package_json_imports && spec.starts_with(b"#") { + if self.options.has_imports_feature() && spec.starts_with(b"#") { found = self.package_imports(spec, from_dir, look); } if let Found::No = found { @@ -2532,19 +2586,6 @@ impl<'h> Resolver<'h> { format == ResolutionMode::Import } - /// `parseTaskData.packageId` of the file at `path`, as a key: `collectFiles` has one file in - /// the program for all that have the same. `None`: no resolution to the file has an id. - pub fn package_id(&self, path: &[u8]) -> Option> { - let mut buffer = path_buffer_pool::get(); - let path = to_path_in(path, self.host.is_case_sensitive(), &mut buffer[..]); - // The resolver of a referenced project resolves the imports of its files. - let id = std::iter::once(self) - .chain(&self.redirected) - .find_map(|resolver| resolver.package_ids.get_ref(&*path))?; - let (version, peers) = (id.version, id.peer_dependencies); - Some([id.name, b"@", version, peers, b"/", id.sub_module_name].concat()) - } - /// `resolved.packageId = getPackageId(resolved.path, packageInfo)` for the file at `found`. /// `package` is `packageInfo`, the `package.json` in `directory`. `package_id_of` makes the id /// when the search is over. What making it logs is logged here. @@ -2639,7 +2680,7 @@ impl<'h> Resolver<'h> { } /// `ResolvedFileName`, `IsExternalLibraryImport` and `PackageId`. - fn resolve_type_reference_and_id( + pub fn resolve_type_reference_and_id( &self, name: &[u8], from: &[u8], @@ -2713,7 +2754,6 @@ impl<'h> Resolver<'h> { } // `parseTask.addSubTask`: the program has a file under its normalized name. let found = source.unwrap_or_else(|| normalize_path(found)); - self.propagate_package_id(&found, package_id); Some((found, is_external, package_id)) } @@ -3357,7 +3397,7 @@ impl<'h> Resolver<'h> { }; } let package = self.package(&package_dir); - let respects_exports = self.options.resolve_package_json_exports && !look.ignores_exports; + let respects_exports = self.options.has_exports_feature() && !look.ignores_exports; let exports = package .and_then(|p| p.json.get(b"exports")) .filter(|_| respects_exports); @@ -3693,7 +3733,17 @@ impl<'h> Resolver<'h> { 6404, &[Arg::Bytes(field), Arg::Bytes(key), Arg::Bytes(&filled)], ); - let named = join(package_dir, &filled); + // `strings.ReplaceAll(resolvedTarget, "*", subpath)`: a `*` in the directory of the + // package is replaced too. + let named = if is_pattern && strings::contains_char(package_dir, b'*') { + let resolved_target = inside(package_dir, target_string); + join( + b"/", + &strings::replace_owned(&resolved_target, b"*", subpath), + ) + } else { + join(package_dir, &filled) + }; let input = self.input_file_for(&named, subpath, package_dir, is_imports, look); let found = match input { Found::No => Found::of(self.named_file(&named, target_string, look)), @@ -3874,6 +3924,38 @@ pub fn resolve_config( resolver.resolve_with(module_name, containing_file, look) } +/// `c` is not assigned in Unicode 15, whose tables Go's `unicode` package and `ToUpperJS` have, and +/// has another case in the tables of `char`, which are those of Unicode 17. +pub(crate) fn is_cased_since_unicode_16(c: char) -> bool { + matches!( + c, + '\u{1C89}'..='\u{1C8A}' + | '\u{A7CB}'..='\u{A7CF}' + | '\u{A7D2}' + | '\u{A7D4}' + | '\u{A7DA}'..='\u{A7DC}' + | '\u{10D50}'..='\u{10D65}' + | '\u{10D70}'..='\u{10D85}' + | '\u{16EA0}'..='\u{16EB8}' + | '\u{16EBB}'..='\u{16ED3}' + ) +} + +/// `char::to_lowercase` by the tables of Unicode 15. +pub(crate) fn to_lowercase_unicode_15(c: char) -> impl Iterator { + let is_unmapped = is_cased_since_unicode_16(c); + let mapped = c.to_lowercase().filter(move |_| !is_unmapped); + mapped.chain(is_unmapped.then_some(c)) +} + +/// `char::to_uppercase` by the tables of Unicode 15. +pub(crate) fn to_uppercase_unicode_15(c: char) -> impl Iterator { + let is_unmapped = + is_cased_since_unicode_16(c) || c.to_uppercase().any(is_cased_since_unicode_16); + let mapped = c.to_uppercase().filter(move |_| !is_unmapped); + mapped.chain(is_unmapped.then_some(c)) +} + /// The same character for all that `unicode.SimpleFold` leads to from `c`: those that differ from /// it only in case. fn simple_fold(c: char) -> char { @@ -3888,8 +3970,8 @@ fn simple_fold(c: char) -> char { if matches!(c, '\u{130}' | '\u{131}') { return c; } - let upper = simple(c.to_uppercase(), c); - simple(upper.to_lowercase(), upper) + let upper = simple(to_uppercase_unicode_15(c), c); + simple(to_lowercase_unicode_15(upper), upper) } /// `EquateStringCaseInsensitive`, which is `strings.EqualFold`. @@ -3931,7 +4013,7 @@ fn is_falsy(json: &Json) -> bool { /// `objectKind` #[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ObjectKind { +pub(crate) enum ObjectKind { Subpaths, Conditions, Imports, @@ -3939,7 +4021,7 @@ enum ObjectKind { } /// `initObjectKind`: what the keys of an object in `exports` or `imports` are. -fn object_kind(entries: &[(Vec, Json)]) -> ObjectKind { +pub(crate) fn object_kind(entries: &[(Vec, Json)]) -> ObjectKind { let (mut seen_dot, mut seen_hash, mut seen_other) = (false, false, false); for (key, _) in entries { match key.first() { @@ -3973,6 +4055,15 @@ fn json_type(json: &Json) -> &'static [u8] { } } +/// `Expected.Value` of the field `name` of the `package.json` `json`, a `map[string]string`, +/// whatever `Valid` is. If it is false, the last name can be there twice. +fn get_map_value<'j>(json: &'j Json, name: &[u8]) -> &'j [(Vec, Json)] { + let fields = json.as_object().unwrap_or_default().iter(); + (fields.filter(|field| field.0 == name)) + .find_map(|field| field.1.as_object()) + .unwrap_or_default() +} + /// `validatePackageJSONField`: the field `name` of the `package.json` `json`, if `read` accepts it /// as a value of the type `expected`. fn validate_package_json_field<'j, T>( diff --git a/src/sema/standalone/hir_dump.rs b/src/sema/standalone/hir_dump.rs index eaf48fb19541..1cd71a48d475 100644 --- a/src/sema/standalone/hir_dump.rs +++ b/src/sema/standalone/hir_dump.rs @@ -98,12 +98,14 @@ pub fn dump_and_orphans(file: &File, atoms: &Interner) -> (String, Vec) jsx_expressions, jsx_pragmas, jsdoc_comments, + jsdoc_asterisks: _, jsdoc_hosts: _, jsdoc_types, jsdoc_modifiers, jsdoc_member_comments: _, jsdoc_param_errors, functions_with_param_tags: _, + unmatched_augments_tags: _, ids: _, numbers: _, exprs: _, @@ -1295,6 +1297,7 @@ impl Dump<'_, '_> { clause_end, namespace_start, named, + has_named_imports: _, type_only, is_deferred, mode, @@ -1410,9 +1413,10 @@ impl Dump<'_, '_> { let d = depth + 1; match kind { TypeNodeKind::Error | TypeNodeKind::UniqueSymbol => self.line(depth, label, &head), - TypeNodeKind::Heritage(expr) => { + TypeNodeKind::Heritage { expr, args } => { self.line(depth, label, &head); self.expr(d, "expr", expr); + self.list(d, "args", args, Self::ty); } TypeNodeKind::Keyword(keyword) => put!(self, depth, label, "{head} {keyword:?}"), TypeNodeKind::Ref { name, args } => { @@ -1674,7 +1678,7 @@ fn stmt_kind_name(kind: StmtKind) -> &'static str { fn type_kind_name(kind: TypeNodeKind) -> &'static str { match kind { TypeNodeKind::Error => "Error", - TypeNodeKind::Heritage(_) => "Heritage", + TypeNodeKind::Heritage { .. } => "Heritage", TypeNodeKind::Keyword(_) => "Keyword", TypeNodeKind::Ref { .. } => "Ref", TypeNodeKind::StringLit(_) => "StringLit", diff --git a/src/sema/standalone/native.rs b/src/sema/standalone/native.rs index 9c93d9ee4161..c24d48048c93 100644 --- a/src/sema/standalone/native.rs +++ b/src/sema/standalone/native.rs @@ -731,6 +731,42 @@ fn __bun_macro_context_get_remap( None } +/// The digits of the mantissa of `text`, from the first that is not 0. +fn mantissa_digits(text: &[u8]) -> impl Iterator { + let end = bun_core::strings::index_of_char_usize(text, b'e').unwrap_or(text.len()); + let digits = text[..end].iter().copied().filter(u8::is_ascii_digit); + digits.skip_while(|&digit| digit == b'0') +} + +/// ECMA-262 `Number::toString`: of two shortest forms that are equally close to `number`, the one +/// whose last digit is even. `text`: `number` as Rust writes it, which takes the upper one. +fn round_tie_to_even(text: &mut [u8], number: f64) { + use std::io::Write; + let end = bun_core::strings::index_of_char_usize(text, b'e').unwrap_or(text.len()); + let Some(last) = end.checked_sub(1) else { + return; + }; + if !text[last].is_ascii_digit() || text[last].is_multiple_of(2) { + return; + } + text[last] -= 1; + let written = core::str::from_utf8(text).ok(); + let lower: Option = written.and_then(|s| s.parse().ok()); + // In a tie the exact value, which has at most 767 digits, is the lower form and a 5. + let mut exact: Vec = Vec::new(); + if lower == Some(number) { + let _ = write!(exact, "{number:.766e}"); + } + let is_tie = { + let mut rest = mantissa_digits(&exact); + let mut halfway = mantissa_digits(text).chain(*b"5"); + halfway.all(|digit| rest.next() == Some(digit)) && rest.all(|digit| digit == b'0') + }; + if !is_tie { + text[last] += 1; + } +} + /// `String(number)`, as `WTF::numberToString` writes it. #[unsafe(no_mangle)] extern "C" fn WTF__dtoa(buf: &mut [u8; 124], number: f64) -> usize { @@ -748,6 +784,7 @@ extern "C" fn WTF__dtoa(buf: &mut [u8; 124], number: f64) -> usize { text.push(b'0'); } else if number.abs() >= 1e21 || number.abs() < 1e-6 { let _ = write!(text, "{number:e}"); + round_tie_to_even(&mut text, number); if let Some(e) = bun_core::strings::index_of_char_usize(&text, b'e') && text.get(e + 1) != Some(&b'-') { @@ -755,6 +792,7 @@ extern "C" fn WTF__dtoa(buf: &mut [u8; 124], number: f64) -> usize { } } else { let _ = write!(text, "{number}"); + round_tie_to_even(&mut text, number); } buf[..text.len()].copy_from_slice(&text); text.len() diff --git a/src/sema/table.rs b/src/sema/table.rs index 42f0284d4815..c855e781aea7 100644 --- a/src/sema/table.rs +++ b/src/sema/table.rs @@ -252,6 +252,13 @@ impl MaybeLocal for FileId { } } +impl MaybeLocal for Sym { + #[inline] + fn is_local(&self) -> bool { + false + } +} + impl MaybeLocal for crate::hir::TypeNodeId { #[inline] fn is_local(&self) -> bool { diff --git a/src/sema/types.rs b/src/sema/types.rs index 38707557c3c4..59a77ef60628 100644 --- a/src/sema/types.rs +++ b/src/sema/types.rs @@ -196,6 +196,19 @@ pub enum StringMappingKind { Uncapitalize, } +/// `checkObjectLiteral` creates a type on every call: the call that created a type of an object literal. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum ObjectLiteralCheck { + /// `checkExpression`, for the parent of the literal. + ForParent, + /// `checkExpressionForMutableLocation`, for `getAssignmentDeclarationInitializerType`. + ForAssignmentDeclaration, + /// `checkExpressionCached`, for `getContextualThisParameterType`, where the parent has left no `links.resolvedType`. + ForThis, + /// The same for the `this` parameter of this member. `checkSignatureDeclaration` requests its type while the literal is checked. + ForThisParameter(FnId), +} + /// The syntax node or declaration whose type is an anonymous object type. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Origin { @@ -203,17 +216,15 @@ pub enum Origin { TypeLiteral(FileId, TypeNodeId), /// `{ [K in T]: U }` Mapped(FileId, TypeNodeId), - /// `{ a: 1 }`, as the type of the expression (`ObjectFlagsObjectLiteral`). `checkObjectLiteral` creates a type on every call. The - /// fields after the node: + /// `{ a: 1 }`, as the type of the expression (`ObjectFlagsObjectLiteral`). The fields after the node: /// 1. `ObjectFlagsJSLiteral`. - /// 2. The type was created for `getAssignmentDeclarationInitializerType` by `checkExpressionForMutableLocation`, not by - /// `checkExpressionCached`. + /// 2. The call of `checkObjectLiteral` that created the type. /// 3. `CONTAINS_WIDENING_TYPE` and `NON_INFERRABLE_TYPE`, propagated from the member types when the type was created. /// 4. `ObjectFlagsFreshLiteral`. - ObjectLiteral(FileId, ExprId, bool, bool, ObjectFlags, bool), + ObjectLiteral(FileId, ExprId, bool, ObjectLiteralCheck, ObjectFlags, bool), /// `getWidenedTypeOfObjectLiteral` of it. The first two fields after the node are the same. The /// last one is `ObjectFlagsNonInferrableType`, which widening preserves. - WidenedLiteral(FileId, ExprId, bool, bool, bool), + WidenedLiteral(FileId, ExprId, bool, ObjectLiteralCheck, bool), /// The constructor function of a class, with its static members. ClassStatic(Sym), /// A function declaration with all its overloads, and the namespace merged with it. @@ -614,10 +625,13 @@ pub enum InstantiationExpression { #[derive(PartialEq, Eq, Hash, Debug)] pub struct Shape<'s> { /// `symbol.Declarations[0]` of a synthesized type that has the symbol of an object literal - /// (`getSpreadType`, `getWidenedTypeOfObjectLiteral`), or of a binding element (`getRestType`, - /// when there is an index signature): the file and the position, by which `CompareTypes` - /// orders, and the object literal, if it is one. + /// (`getSpreadType`, `getWidenedTypeOfObjectLiteral`), or of a binding element (`getRestType`): + /// the file and the position, by which `CompareTypes` orders, and the object literal, if it is + /// one. pub symbol_declared_at: Option<(FileId, u32, ExprId)>, + /// `t.symbol` of a type that `getRestType` creates for a destructuring assignment: that of the + /// type that is destructured. + pub symbol: Option, /// In declaration order, own before inherited. pub props: ArenaVec<'s, Prop<'s>>, pub call: ArenaVec<'s, SigId>, @@ -632,8 +646,13 @@ pub struct Shape<'s> { pub contains_widening_type: bool, /// `ObjectFlagsJSLiteral` pub is_js_literal: bool, + /// `ObjectFlagsObjectRestType` + pub is_object_rest_type: bool, /// For a type created by `getInstantiationExpressionType`. pub instantiation_expression: Option, + /// `t.target` of an instantiation of such a type: `getObjectTypeInstantiation` instantiates + /// the members of the type as created. + pub instantiation_target: Option, /// For a type created by `createDefaultPropertyWrapperForModule`: `originalSymbol`, the module, /// which is the `Parent` of its `default`. pub default_of: Option, @@ -654,6 +673,10 @@ pub struct Shape<'s> { /// never instantiated, and nothing is inferred to it. It has no implicit index signature /// (`isObjectTypeWithInferableIndex`). pub has_no_instantiable_symbol: bool, + /// For a type created by `getTypeFromObjectBindingPattern`, which creates a new type on every + /// call, and for what `getWidenedTypeOfObjectLiteral` makes of it: the file and the position + /// of the pattern. + pub pattern_at: Option<(FileId, u32)>, /// `t.mapper` of a type that `getObjectTypeInstantiation` instantiates whatever its members /// mention: it has the symbol of an object literal (`getSpreadType`, /// `getWidenedTypeOfObjectLiteral`), `ObjectFlagsObjectRestType` or @@ -722,6 +745,15 @@ impl Literalness { | Literalness::Partial ) } + + /// `patternForType[t] != nil` for a type that no expression has. + #[inline] + pub fn is_of_pattern(self) -> bool { + matches!( + self, + Literalness::Pattern | Literalness::PatternWithComputedNames + ) + } } impl<'s> Shape<'s> { @@ -729,6 +761,7 @@ impl<'s> Shape<'s> { pub fn new_in(arena: &'s Arena) -> Shape<'s> { Shape { symbol_declared_at: None, + symbol: None, props: ArenaVec::new_in(arena), call: ArenaVec::new_in(arena), construct: ArenaVec::new_in(arena), @@ -737,12 +770,15 @@ impl<'s> Shape<'s> { is_regular: false, contains_widening_type: false, is_js_literal: false, + is_object_rest_type: false, instantiation_expression: None, + instantiation_target: None, default_of: None, spread_of: None, spread_rank: 0, single_signature_arguments: None, has_no_instantiable_symbol: false, + pattern_at: None, mapper: MapperId::IDENTITY, } } @@ -968,7 +1004,9 @@ bitflags::bitflags! { /// Is or contains a mapped type with `Provenance::stored_under` for which /// `couldContainTypeVariables` holds. Instantiation changes it although it references no /// type parameter: `getObjectTypeInstantiation` looks it up under its own key, where - /// another type is. + /// another type is. The same for a conditional type that stores an alias: + /// `getConditionalTypeInstantiation` looks it up under the key without one. And for a union + /// with `Provenance::has_other_instantiation`. const HAS_OTHER_INSTANTIATION = 256; } } @@ -993,6 +1031,16 @@ pub struct Provenance<'s> { /// `ObjectFlagsArrayLiteral`: the clone of a type reference that `createArrayLiteralType` /// creates (`cloneTypeReference`), once per reference. pub is_array_literal: bool, + /// `patternForType[t] != nil` for the clone of a tuple type that + /// `getTypeFromArrayBindingPattern` creates with `includePatternInType`. + pub is_array_pattern: bool, + /// `couldContainTypeVariables`, for a union that `getUnionTypeWorker` creates with an alias and + /// an `origin` of one type, a named union that has every member. `instantiateTypeWorker` does + /// not return it unchanged, because it compares no alias with `alias`, and `getUnionTypeEx` of + /// the one type is that type. Also for a union or an intersection with a constituent that has + /// `ObjectFlags::HAS_OTHER_INSTANTIATION`, if `alias` has no type arguments and is not declared + /// at the top level of a file (`isNonGenericTopLevelType`). + pub has_other_instantiation: bool, } /// `getTypeInstantiationKey`, for `ObjectType.instantiations` of a mapped type. @@ -1195,6 +1243,8 @@ pub struct ProvenanceKey<'a> { pub is_enum: bool, pub stored_under: Option, pub is_array_literal: bool, + pub is_array_pattern: bool, + pub has_other_instantiation: bool, } impl ProvenanceKey<'_> { @@ -1204,6 +1254,8 @@ impl ProvenanceKey<'_> { && !self.is_enum && self.stored_under.is_none() && !self.is_array_literal + && !self.is_array_pattern + && !self.has_other_instantiation } fn is(self, provenance: &Provenance) -> bool { @@ -1224,6 +1276,8 @@ impl ProvenanceKey<'_> { && self.is_enum == provenance.is_enum && self.stored_under == provenance.stored_under && self.is_array_literal == provenance.is_array_literal + && self.is_array_pattern == provenance.is_array_pattern + && self.has_other_instantiation == provenance.has_other_instantiation } fn to_provenance<'s>(self, arena: &'s Arena) -> Provenance<'s> { @@ -1241,6 +1295,8 @@ impl ProvenanceKey<'_> { is_enum: self.is_enum, stored_under: self.stored_under, is_array_literal: self.is_array_literal, + is_array_pattern: self.is_array_pattern, + has_other_instantiation: self.has_other_instantiation, } } } @@ -2154,6 +2210,30 @@ impl<'p, 's> Types<'p, 's> { } } + /// Whether a union or an intersection with `key` and `origin` takes + /// `ObjectFlags::HAS_OTHER_INSTANTIATION` from a constituent. + pub fn has_constituent_with_other_instantiation( + &self, + key: TypeKey<'_>, + origin: OriginKey<'_>, + ) -> bool { + let members: &[TypeId] = match key { + TypeKey::Data(TypeData::Union(members) | TypeData::Intersection(members)) => { + &members[..] + } + TypeKey::Union(members) | TypeKey::Intersection(members) => members, + _ => &[], + }; + let of_origin: &[TypeId] = match origin { + OriginKey::Union(types) | OriginKey::Intersection(types) => types, + OriginKey::None | OriginKey::Keyof(_) => &[], + }; + members.iter().chain(of_origin).any(|&t| { + self.object_flags(t) + .contains(ObjectFlags::HAS_OTHER_INSTANTIATION) + }) + } + fn new_record(&self, created: Made<'s>, id: u32) -> TypeRecord<'s> { let data = &created.0; let may_be_reduced = match data { @@ -2180,18 +2260,34 @@ impl<'p, 's> Types<'p, 's> { flags |= ObjectFlags::COULD_CONTAIN_TYPE_VARIABLES; } if let Some(provenance) = created.1.as_deref() { + // `instantiateTypeWorker` instantiates a union through its origin. + if let UnionOrigin::Union(types) | UnionOrigin::Intersection(types) = &provenance.origin + { + for &t in types.iter() { + flags |= self.object_flags(t) & ObjectFlags::HAS_OTHER_INSTANTIATION; + } + } if let Some(key) = provenance.stored_under { flags.set( ObjectFlags::HAS_OTHER_INSTANTIATION, key.could_contain_type_variables, ); } - // `isNonGenericTopLevelType` - if (provenance.alias.as_ref()).is_some_and(|alias| alias.1.is_empty()) { + // `isNonGenericTopLevelType`, see `has_other_instantiation`. Nothing asks it of a result + // of `getObjectTypeInstantiation`, which sets the flag from the type arguments. + if is_union_or_intersection + && (provenance.alias.as_ref()).is_some_and(|alias| alias.1.is_empty()) + { flags.remove(ObjectFlags::HAS_OTHER_INSTANTIATION); } - // `createArrayLiteralType` - if provenance.is_array_literal { + if provenance.has_other_instantiation { + flags |= ObjectFlags::HAS_OTHER_INSTANTIATION; + } + if provenance.alias.is_some() && matches!(data, TypeData::Cond { .. }) { + flags |= ObjectFlags::HAS_OTHER_INSTANTIATION; + } + // `createArrayLiteralType`, `getTypeFromArrayBindingPattern` + if provenance.is_array_literal || provenance.is_array_pattern { flags |= ObjectFlags::CONTAINS_OBJECT_OR_ARRAY_LITERAL; } } @@ -2371,6 +2467,13 @@ impl<'p, 's> Types<'p, 's> { .is_some_and(|provenance| provenance.is_array_literal) } + /// See `Provenance::is_array_pattern`. + #[inline] + pub fn is_array_pattern(&self, id: TypeId) -> bool { + self.provenance(id) + .is_some_and(|provenance| provenance.is_array_pattern) + } + fn intern_new(&self, created: Made<'s>) -> TypeId { TypeId(intern_record( (&self.published.types, self.own, Kind::Type), @@ -2880,6 +2983,7 @@ has_no_references!( StringMappingKind, PropFlags, ObjectFlags, + ObjectLiteralCheck, Literalness, ); @@ -2997,6 +3101,7 @@ follow_enum!(InstantiationExpression { }); follow_struct!(Shape<'_> { symbol_declared_at, + symbol, props, call, construct, @@ -3005,12 +3110,15 @@ follow_struct!(Shape<'_> { is_regular, contains_widening_type, is_js_literal, + is_object_rest_type, instantiation_expression, + instantiation_target, default_of, spread_of, spread_rank, single_signature_arguments, has_no_instantiable_symbol, + pattern_at, mapper }); follow_struct!(SigParam { @@ -3033,7 +3141,9 @@ follow_struct!(Provenance<'_> { origin, is_enum, stored_under, - is_array_literal + is_array_literal, + is_array_pattern, + has_other_instantiation }); follow_struct!(InstantiationKey { type_arguments, @@ -3238,6 +3348,7 @@ clone_in_struct!(Prop { }); clone_in_struct!(Shape { symbol_declared_at, + symbol, props, call, construct, @@ -3246,12 +3357,15 @@ clone_in_struct!(Shape { is_regular, contains_widening_type, is_js_literal, + is_object_rest_type, instantiation_expression, + instantiation_target, default_of, spread_of, spread_rank, single_signature_arguments, has_no_instantiable_symbol, + pattern_at, mapper }); clone_in_enum!(SigData { @@ -3266,7 +3380,9 @@ clone_in_struct!(Provenance { origin, is_enum, stored_under, - is_array_literal + is_array_literal, + is_array_pattern, + has_other_instantiation }); clone_in_enum!(UnionOrigin { None, @@ -3513,6 +3629,8 @@ fn content_of_type(created: &Made, of: &[Vec; 5]) -> ContentHash { is_enum, stored_under, is_array_literal, + is_array_pattern, + has_other_instantiation, } = &**provenance; alias.visit(&mut content); match origin { @@ -3525,6 +3643,8 @@ fn content_of_type(created: &Made, of: &[Vec; 5]) -> ContentHash { is_enum.visit(&mut content); stored_under.visit(&mut content); is_array_literal.visit(&mut content); + is_array_pattern.visit(&mut content); + has_other_instantiation.visit(&mut content); } content.lanes.0 } diff --git a/src/sema/verify.rs b/src/sema/verify.rs index 0831fc927df6..06de01023776 100644 --- a/src/sema/verify.rs +++ b/src/sema/verify.rs @@ -39,7 +39,7 @@ fn parsed_list(value: &Json) -> Option<&[Json]> { } /// `IsIdentifierText` -fn is_identifier_text(text: &[u8]) -> bool { +pub(crate) fn is_identifier_text(text: &[u8]) -> bool { let (first, size) = lexer::char_and_size(text, 0); lexer::is_identifier_start(first as u32) && lexer::end_of_run(text, size, lexer::is_type_script_identifier_part) == text.len() @@ -272,7 +272,7 @@ pub(crate) fn relative_from_file(from: &[u8], to: &[u8], is_case_sensitive: bool /// `verifyProjectReferences`: the diagnostics for the projects `root` references, directly or /// transitively, each with the configuration file that references it. `resolved`: /// `configToProjectReference`, the project of the configuration file with a `tspath.Path`, if the -/// file exists. +/// file can be read. pub fn verify_project_references<'a>( root: &'a Project, resolved: &dyn Fn(&[u8]) -> Option<&'a Project>, diff --git a/test/cli/check/check.test.ts b/test/cli/check/check.test.ts index c2bddc65af0e..019b4df0783f 100644 --- a/test/cli/check/check.test.ts +++ b/test/cli/check/check.test.ts @@ -42,6 +42,9 @@ const withResolveJsonModule = JSON.stringify({ compilerOptions: { ...JSON.parse(tsconfig).compilerOptions, resolveJsonModule: true }, }); +// `"".repeat` is slow in debug builds of JavaScriptCore. +const repeat = (text: string, count: number) => Buffer.alloc(text.length * count, text).toString(); + function project(files: Record) { return tempDir("bun-check", { "tsconfig.json": tsconfig, @@ -2778,6 +2781,46 @@ export const wrong: number = { ...tool, kind: 1 }; ); }); + test("a type that is nested too deeply to be printed whole loses no error", async () => { + // The frames of a build that is not optimised are larger: at 1,000 levels the check itself runs out of stack there. + const depth = isDebug || isASAN ? 100 : 1000; + using dir = project({ + "a.ts": `declare const x: ${repeat("{ a: ", depth)}1${repeat(" }", depth)}; +export const wrong: number = x; +`, + }); + const { stdout, stderr, exitCode } = await check(dir, ["--noErrorTruncation"]); + expect(stdout).toStartWith("a.ts(2,14): error TS2322: Type '{ a: { a: { a: { a: { a: { a: "); + expect(stdout).toEndWith(" }; }; }' is not assignable to type 'number'."); + expect(stderr.split("\n")[0]).toBe("Found 1 error in 1 file, checked 1 file [time]"); + expect(exitCode).toBe(1); + }); + + test.each([ + "@overload", + "@callback", + "@param {Object} a", + "@param {object[]} a", + "@template T @param {Object} a", + "@callback @param {Object} a", + ])("a JSDoc comment of 20,000 times %j, each nested in the last", async tags => { + using dir = project({ + "a.ts": `/** {@link f} ${repeat(`${tags} `, 20_000)}*/ +export function f() {} +const wrong: number = ""; +`, + }); + const { stdout, stderr, exitCode } = await check(dir, ["--noUnusedLocals"]); + expect(stdout).toMatchInlineSnapshot(` + "a.ts(3,7): error TS2322: Type 'string' is not assignable to type 'number'. + a.ts(3,7): error TS6133: 'wrong' is declared but its value is never read." + `); + expect(stderr.split("\n")[0]).toBe( + "error: ran out of stack in a.ts. This is a bug in Bun: errors in this file may be missing.", + ); + expect(exitCode).toBe(1); + }); + const isolatedDeclarations = ["--declaration", "true", "--isolatedDeclarations", "true"]; test("isolatedDeclarations: every property of `export default {} satisfies T` is reported", async () => { @@ -13766,7 +13809,7 @@ export const deferred: Deferred<"a"> = 1; }); const { stdout, exitCode } = await check(dir); // The type has a level for every round up to the limit. - expect(stdout.replace("x".repeat(99), "<99 x>")).toMatchInlineSnapshot(` + expect(stdout.replace(repeat("x", 99), "<99 x>")).toMatchInlineSnapshot(` "a.ts(2,43): error TS2589: Type instantiation is excessively deep and possibly infinite. a.ts(3,40): error TS2589: Type instantiation is excessively deep and possibly infinite. a.ts(4,54): error TS2589: Type instantiation is excessively deep and possibly infinite. @@ -14366,6 +14409,53 @@ export function f(rest: T) { ); }); + // As in tsc: without its options nothing can be checked. To a build the file is not there. + test.skipIf(canReadEverything).each([ + [[], "error TS5083: Cannot read file '

/tsconfig.json'."], + [["-p", "."], "error TS5083: Cannot read file '/tsconfig.json'."], + [["-b"], "error TS6053: File '/tsconfig.json' not found."], + ])("a tsconfig.json that cannot be read stops the check: %j", async (args, expected) => { + using dir = project({ "tsconfig.json": `{}`, "a.ts": `export const wrong: number = "";\n` }); + chmodSync(join(String(dir), "tsconfig.json"), 0o000); + const { stdout, exitCode } = await check(dir, args); + expect(stdout).toBe(expected); + expect(exitCode).toBe(1); + }); + + test.skipIf(canReadEverything).each([ + [[], []], + [["-b"], ["error TS6053: File '/lib/tsconfig.json' not found."]], + ])("a referenced tsconfig.json that cannot be read is not found: %j", async (args, first) => { + const compilerOptions = { composite: true, emitDeclarationOnly: true, outDir: "out", lib: ["es5"], types: [] }; + using dir = project({ + "tsconfig.json": JSON.stringify({ compilerOptions, files: ["a.ts"], references: [{ path: "./lib" }] }), + "a.ts": `export const a = 1;\n`, + "lib/tsconfig.json": JSON.stringify({ compilerOptions }), + "lib/l.ts": `export const wrong: number = "";\n`, + }); + chmodSync(join(String(dir), "lib/tsconfig.json"), 0o000); + const { stdout, exitCode } = await check(dir, args); + const lines = stdout.split("\n").map(line => line.replace(/^tsconfig\.json\(\d+,\d+\): /, "tsconfig.json: ")); + expect(lines).toEqual([...first, "tsconfig.json: error TS6053: File '/lib' not found."]); + expect(exitCode).toBe(1); + }); + + // How deep the parser goes depends on the stack of the platform. Whatever it says, the file can be read. + test.each([[[]], [["-b"]]])( + "the files of a tsconfig.json that is nested too deeply are checked: %j", + async args => { + const depth = 100_000; + using dir = project({ + "tsconfig.json": `{ "a": ${repeat("[", depth)}${repeat("]", depth)} }`, + "a.ts": `export const wrong: number = "";\n`, + }); + const { stdout, exitCode } = await check(dir, args); + expect(stdout).toContain("a.ts(1,14): error TS2322: Type 'string' is not assignable to type 'number'."); + expect(stdout).not.toContain("not found"); + expect(exitCode).toBe(1); + }, + ); + test("-p with a path that does not exist", async () => { using dir = project({}); const { stdout, stderr, exitCode } = await check(dir, ["-p", "nowhere"]); @@ -16239,7 +16329,7 @@ describe.concurrent("--check", () => { "const x = [[[[[[[[[[[[[[[[[[", "declare function f(a: any): any;\nconst x = f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(", "declare function f(a: any): any;\nconst x = (f([(f([(f([(f([(f([(f([", - `const x = ${"{ a: ".repeat(18)}`, + `const x = ${repeat("{ a: ", 18)}`, "const x = ((((((((((((((((((", "interface I { m(export= x: string): any; }", "interface I { n(,): any; }", @@ -16372,7 +16462,7 @@ describe.concurrent("--check", () => { n, ) .map(() => "while (c) { x = h(x);") - .join(" ")} ${"}".repeat(n)} return x; }`, + .join(" ")} ${repeat("}", n)} return x; }`, ], [ "a chain of `&&`", @@ -16393,7 +16483,7 @@ describe.concurrent("--check", () => { [ "a chain of method calls", size, - n => `declare const a: { m(): typeof a };\nexport const r = a${".m()".repeat(n)};`, + n => `declare const a: { m(): typeof a };\nexport const r = a${repeat(".m()", n)};`, ], [ // TypeScript needs seconds for 400 members too. @@ -16432,11 +16522,11 @@ describe.concurrent("--check", () => { .map(i => `export function f${i}() { return f${i + 1}(); }`) .join("\n")}\nexport function f${n}() { return 1; }`, ], - ["nested object literals", size, n => `export const r = ${"{ a: ".repeat(n)}1${" }".repeat(n)};`], + ["nested object literals", size, n => `export const r = ${repeat("{ a: ", n)}1${repeat(" }", n)};`], [ "nested array types", size, - n => `export type T = ${"Array<".repeat(n)}number${">".repeat(n)};\nexport declare const t: T;`, + n => `export type T = ${repeat("Array<", n)}number${repeat(">", n)};\nexport declare const t: T;`, ], [ "a recursive conditional type", diff --git a/test/cli/check/differential-cases.json b/test/cli/check/differential-cases.json index cce56ea014bc..f406e2075262 100644 --- a/test/cli/check/differential-cases.json +++ b/test/cli/check/differential-cases.json @@ -635,6 +635,25 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, + "03-SC1": { + "files": { + "a.ts": "declare function f(): \"a\";\nclass C14 { [k: string]: number; [f()]() {} }\nclass C15 { [k: string]: number; get [f()]() { return \"\"; } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "03-SC10": { + "files": { + "a.ts": "class B { static x: number; y!: string; }\ntype TB = typeof B;\nclass D1 implements TB {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "03-SC2": { + "files": { + "a.d.ts": "declare enum E { A }\n", + "b.ts": "enum E { B }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"skipLibCheck\": true } }\n" + } + }, "03-SC3": { "files": { "a.ts": "const x = 1; type T = 1;\nexport = x;\nexport { T as Y };\nexport const Y = 1;\n", @@ -642,6 +661,19 @@ "z.ts": "const sentinel: number = \"\";\nexport {};\n" } }, + "03-SC4": { + "files": { + "a.ts": "export type F = ({ a, ...r }: { a: number; b: number }) => void;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2017\", \"importHelpers\": true } }\n" + } + }, + "03-SC5": { + "files": { + "a.ts": "import \"./m\";\ndeclare module \"./m\" {\n import z = require(\"./m\");\n}\nconst sentinel: number = \"\";\n", + "m.ts": "export const a = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, "03-SC6": { "files": { "a.d.ts": "declare module \"x5\" { namespace N { interface I {} } export = N; }\n", @@ -650,6 +682,26 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" } }\n" } }, + "03-SC7": { + "files": { + "a.ts": "class B { x: number = 1; }\nclass D extends B { x: number; }\nconst sentinel: number = \"\";\n", + "b.ts": "interface D { x: number }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"strictPropertyInitialization\": false } }\n" + } + }, + "03-SC8": { + "files": { + "a.ts": "import { K } from \"./m\";\nexport function f1() { const u3 = 1; export { u3 }; }\nexport function f4() { export { K as KK }; }\nexport function f7() { const u = 1; export default u; }\nexport function f8() { export default { a: 1, a: 2 }; }\nconst sentinel: number = \"\";\n", + "m.ts": "export class K {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "03-SC9": { + "files": { + "a.ts": "declare const x: any;\nwith (x) { interface K { a: number; a: string } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, "04-C10a": { "files": { "a.ts": "const sentinel: number = \"\";\n", @@ -2145,6 +2197,63 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, + "10-SC1": { + "files": { + "a.ts": "export {};\ntype B = { k: \"a\"; p: 1 } & { k: T; q: 2 };\ninterface X extends B { own: 3 }\ndeclare const xb: X<\"b\">;\nxb.k; xb.p; xb.q;\nconst lit: X<\"b\"> = { own: 3 };\nconst sentinel: number = \"\";\n", + "b.ts": "export {};\ntype V = [1, ...T];\ninterface X extends V { }\ndeclare const x: X<[2, 3]>;\nconst y: [1, 2, 3] = x;\nconst len: 3 = x.length;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "10-SC10": { + "files": { + "a.ts": "declare let n: never; declare const kn: number;\nclass C1 { [kn] = 1; [+1] = \"s\"; }\nn = new C1()[5];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "10-SC11": { + "files": { + "g.ts": "interface Array extends Array {}\ninterface ReadonlyArray extends ReadonlyArray {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "10-SC12": { + "files": { + "a.ts": "type F1 = (this, string) => void;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "10-SC3": { + "files": { + "j.js": "/** @type {{ new(): {}, a: string[] }} */\nconst CE2 = class {};\nCE2.a = [];\nfunction F() {}\n/** @type {{ (): void, b: string[] }} */\nF.a = function () {};\nF.a.b = [];\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "10-SC5": { + "files": { + "a.ts": "export {};\ndeclare function isT(x: T | undefined): x is T;\ndeclare function wrap(f: (a: A) => a is B): (a: A) => a is B;\nconst g = wrap(isT);\ndeclare const v: \"a\" | undefined;\nif (g(v)) { v.length; }\ndeclare let n: never; n = g;\nconst sentinel: number = \"\";\n", + "b.ts": "export {};\ndeclare function mk(): (a: A) => a is B;\nconst f: (x: T | undefined) => x is T = mk();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "10-SC7": { + "files": { + "j.js": "/** @type {{ m(): void, n: () => void }} */\nconst o = { m(a) {}, n(a) {} };\n/** @param {{ m(): void }} x */\nfunction take(x) {}\ntake({ m(a) {} });\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "10-SC8": { + "files": { + "a.ts": "interface Foo {}\nexport type F1 = (Foo) => void;\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noImplicitAny\": false, \"noUnusedLocals\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "10-SC9": { + "files": { + "m.js": "Object.defineProperty(exports, \"p6\", { value: undefined });\nObject.defineProperty(exports, \"p7\", { get() { return null; } });\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n", + "u.ts": "import m = require(\"./m\");\ndeclare let n: never;\nn = m.p6; n = m.p7;\nconst sentinel: number = \"\";\n" + } + }, "11-C1": { "files": { "a.ts": "interface Thenable { then(cb: number): void }\ndeclare const th: Thenable;\nasync function* w6() { yield th; }\nconst sentinel: number = \"\";\n", @@ -3541,24 +3650,60 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"exactOptionalPropertyTypes\": true } }\n" } }, + "17-SC1": { + "files": { + "a.ts": "type Digits = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype T1 = `${Digits}${Digits}${Digits}${Digits}` | undefined;\ntype T2 = { a: string } | { b: number };\ndeclare let y: T1 & T2; declare let z: T1 | T2;\nconst c2: { p: T1 | T2; q: number } = { p: y, q: \"\" };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, + "17-SC2": { + "files": { + "a.ts": "type Digits = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype T1 = `${Digits}${Digits}${Digits}${Digits}` | undefined;\ntype T2 = { a: string } | { b: number };\ndeclare let y: T1 & T2; declare let z: T1 | T2;\nclass KA { p!: T1 | T2 } class KB extends KA { declare p: T1 & T2 }\nconst sentinel: number = \"\";\n", + "b.ts": "type CA = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype CB = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: number } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype CA2 = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ndeclare let a: CA; declare let b: CB; declare let a2: CA2;\nclass LA { p!: CA } class LB extends LA { declare p: CB }\nexport {};\n", + "c.ts": "type MA = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype MB = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: number } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype MA2 = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ndeclare let a: MA; declare let b: MB; declare let a2: MA2;\ninterface Face { p: MA } class Impl implements Face { p!: MB }\nexport {};\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, "17-SC3": { "files": { "a.ts": "type A = { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: { [k: string]: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, + "17-SC4": { + "files": { + "a.ts": "type Digits = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype T1 = `${Digits}${Digits}${Digits}${Digits}` | undefined;\ntype T2 = { a: string } | { b: number };\ndeclare let y: T1 & T2; declare let z: T1 | T2;\nz = y; z = y;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, "17-SC4b": { "files": { "a.ts": "type Digits = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype T1 = `${Digits}${Digits}${Digits}${Digits}` | undefined;\ntype T2 = { a: string } | { b: number };\ndeclare let y: T1 & T2; declare let z: T1 | T2;\ntype F = T; type G = F;\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, + "17-SC5": { + "files": { + "a.ts": "type A = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype B = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: number } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype A2 = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ndeclare let a: A; declare let b: B; declare let a2: A2;\nclass KA { static p: A } class KB extends KA { static p: B }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, "17-SC6": { "files": { "a.js": "/** @type {number[]} */\nconst x1 = [/** @type {string} */ (\"\")];\n/** @type {number[]} */\nconst y2 = [/** @type {string} */ (/** @type {any} */ (\"\"))];\n/** @type {number} */\nconst sentinel = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" } }, + "17-SS1": { + "files": { + "a.ts": "type La = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype Lb = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype Ta = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: La } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype Tb = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: Lb } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ndeclare let lb: Lb; const la: La = lb;\nclass K { m(x: Tb): void; m(x: Ta) {} }\nconst sentinel: number = \"\";\n", + "b.ts": "type A = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype B = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: number } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ntype A2 = { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: { a: string } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } };\ndeclare let a: A; declare let b: B; declare let a2: A2;\nfunction ov(x: A): void; function ov(x: B): void; function ov(x: B) {}\nexport {};\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, "18-C10a": { "files": { "a.ts": "declare function f1(...args: [a: number, ...b: [string]]): void;\nconst x1: 0 = f1;\nconst sentinel: number = \"\";\n", @@ -4938,6 +5083,61 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, + "24-SC1": { + "files": { + "a.ts": "const o1 = { get d(): number { return 1 }, set d(v: string | number) {} };\nconst sp = { ...o1 }; sp.d = \"x\";\nconst s1: string = sp;\ninterface I { get d(): number; set d(v: string | number); r: 1 }\ndeclare const i: I;\nconst { r, ...rest } = i; rest.d = \"x\";\n// C8 of the report: the symbol that is handed on also keeps CheckFlagsReverseMapped.\ninterface IB { a: { v: number }; b: { v: string } } declare const ib: IB;\ndeclare function un7(b: { [K in keyof T]: { [L in keyof T[K]]: { v: T[K][L] } } }): T;\nconst e = un7({ p: ib, q: { r: { v: 1 } } });\nconst r8: string = { ...e };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "24-SC10": { + "files": { + "a.ts": "declare const o: { get a(): 1; set a(v: 2) };\nconst v: string = null! as { k: typeof o; fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: 1; p0: 1; p1: 1; p2: 1; p3: 1; p4: 1; p5: 1; p6: 1; p7: 1; p8: 1; p9: 1 };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "24-SC11": { + "files": { + "a.ts": "declare const a: number[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]; const s: string = a;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noErrorTruncation\": true } }\n" + } + }, + "24-SC2": { + "files": { + "a.ts": "import { o, sym } from \"./m\";\nexport const x: number = { a: o };\nexport const sentinel: number = \"\";\n", + "m.ts": "export const sym = Symbol(); export const o = { [sym]: 1 };\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "24-SC3": { + "files": { + "a.ts": "const w2 = (t: T) => ({ ...{}, w: t });\nconst d2: string = w2(w2(w2(w2(w2(w2(w2(w2(w2(w2(w2(w2(w2(w2(1))))))))))))));\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "24-SC4": { + "files": { + "a.ts": "const ar = () => {}; ar['d-e'] = 3; ar['1'] = 1;\nconst t2: string = ar;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "24-SC6": { + "files": { + "a.ts": "const o = { x: 1, m(a: typeof this) { return a.x }, n(a: typeof this.x) { return a } };\nconst q1: number = o;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "24-SC7": { + "files": { + "a.ts": "class C {\n m(u: U): [T, U] { return null! }\n n() { const c = null! as C; const x2: string = c.m; }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "24-SC9": { + "files": { + "a.ts": "declare function f1(...a: number[], ...b: [string, number]): void;\nconst s1: string = f1;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, "25-C1": { "files": { "a.ts": "type U = { k: \"a\"; v: string } | { k: \"b\"; v: number };\nfunction f(u: U | undefined) { if ((u!).k === \"a\") u!.v.length; }\nconst sentinel: number = \"\";\n", @@ -7165,6 +7365,74 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, + "31-SC1": { + "files": { + "a.ts": "declare let c: boolean; declare function fail(): never; declare function assertS(x: unknown): asserts x is string;\ndeclare function get(): (x: unknown) => asserts x is string;\nfunction g1(x: unknown) { for (assertS(x); c;) { x.length; } }\nfunction g2(): number { for (fail(); c;) { } }\nfunction g3() { let y: number; for (fail(); c;) { } y.toFixed(); }\nfunction g4(x: unknown) { for (get()(x); c;) { } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "31-SC10": { + "files": { + "a.ts": "function b1() { let x: arguments; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "31-SC11": { + "files": { + "a.ts": "class S25 { [valu]() { let value = 1 } }\nconst s26 = { [valu]() { let value = 1 } };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "31-SC12": { + "files": { + "a.ts": "class R7 { get g() { switch ((() => { throw 1 })()) { case 1: break } } }\nfunction r1() { switch ((() => { throw 1 })()) { case 1: break } class C { } }\nfunction r3() { switch ((() => { throw 1 })()) { case 1: break } { let a; function a() { } } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowUnreachableCode\": false } }\n" + } + }, + "31-SC2": { + "files": { + "a.ts": "function f1(x: string | number) { const y = (x = 1); const n: never = y; }\nfunction f2(x: string | number) { x = 1; const y = (x = \"a\"); }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "31-SC3": { + "files": { + "a.ts": "import { i1 } from \"./b\";\nexport function k1(\n /** {@link v} */\n a: number) { let v = 1; return a }\nexport function k2(\n /** {@link L} */\n a: number) { type L = 1; return a }\nexport function k3(\n /** {@link i1} */\n a: number) { let i1 = 1; return a + i1 }\nexport const sentinel: number = \"\";\n", + "b.ts": "export const i1 = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "31-SC4": { + "files": { + "a.ts": "export class K {\n /** {@link T} */\n static p = 1\n}\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true, \"noUnusedParameters\": true } }\n" + } + }, + "31-SC5": { + "files": { + "a.ts": "export function k(): number {\n if (Math.random() > 0.5) {\n const limit = 10;\n /** At most {@link limit}. */\n const x = 1;\n return x;\n }\n for (const item of [1]) {\n /** See {@link item}. */\n return 1;\n }\n return 0;\n}\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "31-SC6": { + "files": { + "a.ts": "import { Foo } from \"./b\"; import { Bar } from \"./b\"; import { Baz } from \"./b\";\nexport type F1 = (Foo) => void;\nexport interface F2 { m(Bar): void; (Baz): void }\nexport type F4 = (T) => void;\nexport type F9 = (Local) => void; type Local = 1;\nexport const sentinel: number = \"\";\n", + "b.ts": "export interface Foo { } export interface Bar { } export interface Baz { }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noImplicitAny\": false, \"noUnusedLocals\": true, \"noUnusedParameters\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "31-SC7": { + "files": { + "a.ts": "declare function use(...a: any[]): void;\ntype O = { b?: number } | undefined;\nfunction y1(o: O): number { o?.b ??= 1; }\nfunction y2(o: O) { let x: number; o?.b ||= 1; use(x); }\nfunction y3(o: O, s: string | number) { if (typeof s === \"string\") { o?.b &&= 1; const n: never = s; } }\nclass Y4 { a: number; constructor(o: O) { o?.[\"b\"] ??= 1; } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "31-SC8": { + "files": { + "a.ts": "declare function use(...a: any[]): void; declare function fail(): never; declare function assertS(x: unknown): asserts x is string;\nfunction w1(x: any) { with (fail()) { } use(); }\nfunction w2(x: unknown) { with (assertS(x)) { } const n: never = x; }\ndeclare let o: any;\nfunction w3() { with (o) let a = 1; a; }\nfunction w5() { let a = 1; with (o) let a = 2; a; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowUnreachableCode\": false } }\n" + } + }, "32-C1": { "files": { "a.ts": "class R { readonly x: number = 0; constructor() { (this).x = 1; } }\nconst sentinel: number = \"\";\n", @@ -9436,6 +9704,22 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\", \"moduleResolution\": \"bundler\", \"resolvePackageJsonExports\": false, \"resolvePackageJsonImports\": false }, \"files\": [\"a.ts\"] }\n" } }, + "38-SC3": { + "files": { + "a.ts": "import { make } from \"pkg\"; export const x = make();\n", + "b.ts": "export const sentinel: number = \"\";\n", + "node_modules/pkg/index.d.ts": "import { Inner } from \"./internal\"; export declare function make(): Inner;\n", + "node_modules/pkg/internal.d.ts": "export interface Inner { a: number }\n", + "node_modules/pkg/package.json": "{ \"name\": \"pkg\", \"version\": \"1.0.0\", \"exports\": { \".\": { \"types\": \"./index.d.ts\" } } }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"noEmit\": true, \"types\": [], \"module\": \"node16\", \"declaration\": true, \"resolvePackageJsonExports\": false } }\n" + } + }, + "38-SC5": { + "files": { + "a.ts": "const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"noEmit\": true, \"types\": [], \"lib\": [\"es5\"], \"jsx\": \"react-natİve\" } }\n" + } + }, "39-C10a": { "files": { "a.ts": "import { E } from './b/b';\nE.A;\nconst sentinel: number = \"\";\n", @@ -11301,399 +11585,3494 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "52-L13": { + "51-L01": { "files": { - "a.ts": "declare function count(o: { A: number }): number;\nenum E { A = 1, B = count(E) }\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "f.js": "/** @param {number} z */ function j(z) { const arguments = 1; return z; }\n/** @param {number} z */ function j3(z) { var arguments = 1; return z; }\n/** @param {number} z */ function j8(z) { const { a: arguments } = { a: 1 }; return z; }\n/** @param {number} z */ function j5(z) { class arguments {} return z; }\nfunction k(z) { const arguments = 1; return z; }\nj(1); j3(1); j8(1); j5(1); k(1);\n/** @type {number} */\nconst sentinel = \"\";\nexport { sentinel };\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true, \"noUnusedLocals\": true } }\n" } }, - "52-L15": { + "51-L02": { "files": { - "a.ts": "function next(e: E1) { return e + 1; }\nenum E1 { A = 1, B = next(E1.A) }\ndeclare function make(n: number): E2;\nenum E2 { A = 1, B = make(1) }\ndeclare const first: E3;\nenum E3 { A = 1, B = first }\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "namespace N { module \"x\" {} }\nfunction f() { module \"y\" {} }\nexport { N, f };\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" } }, - "52-L17": { + "51-L05": { "files": { - "a.ts": "function entries(t: T) {\n if (t === null || t === undefined) return;\n for (const [k, v] of Object.entries(t)) v.foo;\n}\nfunction record(t: T) {\n if (t === undefined || t === null) return;\n const r: Record = t;\n}\nfunction both(t: T) { if (t === null) throw 0; if (t === undefined) throw 0; return t; }\nconst y = both(null! as unknown);\nconst r: { [k: string]: number } = y;\nconst { ...rest } = {}; const stays1: { [k: string]: number } = rest;\nconst spread = { ...{} }; const stays2: { [k: string]: number } = spread;\nconst sentinel: number = \"\";\n", + "a.ts": "interface Call { name: string; arguments: string }\n/**\n * Runs a tool call.\n * @param call the call\n */\nexport const handle = (call: Call) => {\n const { name, arguments: args } = call;\n return [name, args];\n};\nexport class K {\n /** @param call the call */\n handle = (call: Call) => {\n const { arguments: args } = call;\n return args;\n };\n}\n/** @param z */\nexport function j(z: number) { const arguments = 1; return z; }\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "54-L19": { + "51-L06a": { "files": { - "a.ts": "export {};\ndeclare function assert(c: unknown): asserts c;\nconst r = h(\"a\");\nfunction h(x: string) {\n if (typeof x !== \"string\") {\n assert(x === k);\n return x;\n }\n return 1;\n}\nconst k = r;\nconst sentinel: number = \"\";\n", - "b.ts": "export {};\ndeclare function assert(c: unknown): asserts c;\nconst r1 = h1(\"a\");\nfunction h1(x: string) {\n if (typeof x !== \"string\") { assert(x instanceof k1); return x; }\n return class {};\n}\nconst k1 = r1;\nconst r2 = h2(\"a\");\nfunction h2(x: string) {\n if (typeof x !== \"string\") { assert(k2 in x); return x; }\n return \"p\";\n}\nconst k2 = r2;\nconst r3 = h3(\"a\");\nfunction h3(x: string) {\n if (typeof x !== \"string\") { assert(x !== k3); return x; }\n return 1;\n}\nconst k3 = r3;\nconst r4 = h4(\"a\");\nfunction h4(x: string) {\n if (typeof x !== \"string\") { assert(true && x === k4); return x; }\n return 1;\n}\nconst k4 = r4;\nconst r5 = h5(null!);\nfunction h5(x: never) {\n assert(x === k5);\n return [x];\n}\nconst k5 = r5;\nconst r6 = h6(\"a\");\nfunction h6(x: string) {\n if (typeof x !== \"string\") { assert(!(x === k6)); return x; }\n return 1;\n}\nconst k6 = r6;\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "f.js": "export const store = {\n /** @param {number} n */\n format(n) { return String(n); },\n pair: /** @type {[number, number]} */ ([1, 2]),\n reset() {\n this.format = (n) => n.toFixed(2);\n this.pair = [3, 4];\n },\n};\nexport const later = {\n reset() {\n this.format = (n) => String(n);\n },\n /** @param {number} n */\n format(n) { return String(n); },\n};\n/** @type {number} */\nexport const sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" } }, - "56-L01": { + "51-L06b": { "files": { - "a.js": "/** @template T */\nclass A { /** @type {T | undefined} */ x = undefined; }\n/** @augments {A<=} */\nclass B extends A {}\n/** @augments {A<<=} */\nclass C extends A {}\n/** @augments A<= */\nclass D extends A {}\n/** @implements {A<=} */\nclass E { x = undefined }\n/** @type {number} */\nconst sentinel = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + "a.ts": "import \"./m\";\nexport const o = { m() { export * as ns from \"./m\"; export * as ns from \"./m\"; } };\nexport const o3 = { m() { export * as ns from \"./m\"; } };\no3.m.ns.v;\nexport const o4 = { m() { export default 1; export default 2; } };\nexport const sentinel: number = \"\";\n", + "m.ts": "export const v = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\" } }\n" } }, - "56-L02": { + "51-L08": { "files": { - "a.ts": "type X = T extends [infer U \\u0065xtends string] ? U : never;\ntype Z = T extends infer U \\u0065xtends string ? U : never;\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "f.js": "const k1 = \"a\", k2 = \"b\";\nexport class Q {\n static m() {\n /** @type {(x: number) => void} */\n this[k1] = (x) => {};\n this[k2] = (y) => {};\n }\n}\nexport class R {\n static m() {\n this[k2] = (y) => {};\n /** @type {(x: number) => void} */\n this[k1] = (x) => {};\n }\n}\n/** @type {number} */\nexport const sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" } }, - "57-L13c": { + "51-L12": { "files": { - "a.ts": "declare const i1: { a: 1 };\nfunction* g1() { yield* i1; }\nfunction* g2() { yield* [1]; }\nfunction* g3() { yield* \"\"; }\nasync function* g4() { yield* i1; }\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es5\"], \"target\": \"es2022\" } }\n" + "a.ts": "export type A1 = typeof import(\"./m\").f<>;\nexport type A2 = typeof import(\"./m\").g<>;\nexport type A3 = typeof import(\"./m\").v<>;\nexport type A4 = typeof import(\"./m\")<>;\nexport const sentinel: number = \"\";\n", + "m.ts": "export function f(x: T): T { return x; }\nexport function g(x: number): number { return x; }\nexport const v = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" } }, - "57-L15": { + "51-L18": { "files": { - "a.js": "function f() {}\nf.a = (f.a, exports);\nexports.b = 1;\n/** @type {number} */\nconst sentinel = \"\";\n", - "b.js": "class C {\n x = (new C().x, module);\n}\nexports.a = 1;\n", - "c.js": "class C {\n static x = (C.x, exports);\n}\nexports.a = 1;\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" } }\n" + "a.ts": "export type F1 = ({ a: b }) => void;\nexport interface I7 { m({ a: b }): void }\nexport declare class C8 { constructor({ a: b }); }\nexport class P { private a = 1; m() { return this.a; } }\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" } }, - "59-L02": { + "51-L19a": { "files": { - "a.ts": "import j from \"./e.json\";\nconst m1: Record = j;\ndeclare function values(r: Record): T[];\nfunction f2(x: unknown, c: Function) {\n if (x instanceof c) {\n const m2: Record = x;\n const m3: { [k: string]: number } = x;\n const m4: Record = x;\n values(x);\n }\n}\nfunction f5(x: { a: 1 } | string, c: Function) {\n if (x instanceof c) {\n const m5: Record = x;\n }\n}\nconst { a, ...rest } = { a: 1 };\nconst m6: Record = rest;\nconst sentinel: number = \"\";\n", - "e.json": "", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"resolveJsonModule\": true, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + "a.ts": "import \"./b\";\nexport declare function f({ a: b }): void;\nexport const sentinel: number = \"\";\n", + "b.ts": "import { f } from \"./a\";\nf({ a: 1 });\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] }, \"files\": [\"a.ts\"] }\n" } }, - "60-L16a": { + "51-L19b": { "files": { - "a.ts": "interface Asserts { str(x: unknown): asserts x is string; num: (x: unknown) => asserts x is number }\ntype Prefixed = { [K in keyof T as `assert${Capitalize}`]: T[K] };\ndeclare const p: Prefixed;\nfunction f(v: unknown, w: unknown) {\n p.assertStr(v);\n v.length;\n p.assertNum(w);\n w.toFixed();\n}\nconst inferred = { bad: (x: unknown): asserts x is string => {} };\ndeclare const q: Prefixed;\nfunction g(v: unknown) { q.assertBad(v); }\nconst sentinel: number = \"\";\n", - "bun.related.txt": "a.ts(5,3) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(6,3) TS18046 'v' is of type 'unknown'.\na.ts(7,3) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(8,3) TS18046 'w' is of type 'unknown'.\na.ts(12,26) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(13,7) TS2322 Type 'string' is not assignable to type 'number'.\n", - "tsc.related.txt": "a.ts(12,26) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\n related a.ts(10,20) 'bad' needs an explicit type annotation.\na.ts(13,7) TS2322 Type 'string' is not assignable to type 'number'.\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "export type F = ({ a: b }) => void;\nexport interface I { m({ a: b }): void }\nexport declare function f({ a: b }): void;\nexport const sentinel: number = \"\";\n", + "b.ts": "import { F, I, f } from \"./a\";\ndeclare const ff: F, i: I;\nff({ a: 1 });\ni.m({ a: 1 });\nf({ a: 1 });\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] }, \"files\": [\"a.ts\", \"b.ts\"] }\n" } }, - "60-L16b": { + "51-L19c": { "files": { - "a.ts": "type A = (x: unknown) => asserts x is string;\nconst inferred = (x: unknown): asserts x is string => {};\nconst obj = { a: inferred, m(x: unknown): asserts x is string {} };\ndeclare const v: unknown;\ninterface I { a: A; m(x: unknown): asserts x is string }\ntype Id = { [K in keyof T]: T[K] };\ndeclare const x1: Id<{ a: A } & typeof obj>; x1.a(v);\ndeclare const x2: Id; x2.a(v);\ndeclare const x3: Id<{ a: A } & { a: A }>; x3.a(v);\ndeclare const x4: Id; x4.a(v); x4.m(v);\ndeclare const x5: Id; x5.a(v);\ndeclare const x6: Id<{ a: A } | { a: A }>; x6.a(v);\ndeclare const x7: Id>; x7.a(v); x7.m(v);\ndeclare const x8: Id>; x8.a(v); x8.m(v);\ndeclare const x9: Id<{ m(x: unknown): asserts x is string } & { m: A }>; x9.m(v);\ndeclare const y1: Id<{ m: A } & { m(x: unknown): asserts x is string }>; y1.m(v);\ndeclare const y2: Id<{ a: A } & { a: (x: unknown) => asserts x is string }>; y2.a(v);\ndeclare const y3: { a: A } & { a: (x: unknown) => asserts x is string }; y3.a(v);\nconst sentinel: number = \"\";\n", - "bun.related.txt": "a.ts(8,46) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\n related a.ts(3,15) 'a' needs an explicit type annotation.\na.ts(12,44) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(14,39) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\n related a.ts(3,15) 'a' needs an explicit type annotation.\na.ts(18,74) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(19,7) TS2322 Type 'string' is not assignable to type 'number'.\n", - "tsc.related.txt": "a.ts(7,46) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(8,46) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(9,44) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(12,44) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(14,39) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\n related a.ts(3,15) 'a' needs an explicit type annotation.\na.ts(15,74) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(16,74) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(17,78) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(18,74) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(19,7) TS2322 Type 'string' is not assignable to type 'number'.\n", + "a.ts": "export declare function p({ a: b }): typeof b;\nexport declare function p2({ a: b }, c: typeof b): void;\nexport namespace NS { export declare function q({ a: b }): void; }\nNS.q({ a: 1 });\nexport const sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "60-L20a": { + "51-L20": { "files": { - "a.ts": "const k = \"foo\";\nclass C1 { get foo() { return 1; } set [k](v: number) {} }\nnew C1().foo = 2;\nclass C3 { static get foo() { return 1; } static set [k](v: number) {} }\nC3.foo = 2;\nclass C6 { set [k](v: number) {} get foo() { return 1; } }\nnew C6().foo = 2;\ndeclare const v5: { get foo(): 1; set [k](v: 2) }; v5.foo = 2;\ninterface I7 { get foo(): 1; set [k](v: 2) } declare const i7: I7; i7.foo = 2;\ndeclare const v7: { foo: number; get [k](): string }; const n7: null = v7; v7.foo = \"\";\nclass C2 { get [k]() { return 1; } set foo(v: number) {} }\nnew C2().foo = 2;\nclass C8 { get [k]() { return 1; } set [k](v: number) {} }\nnew C8().foo = 2;\nconst sentinel: number = \"\";\n", + "a.ts": "class C { private a = 1; b = 2; }\nclass D { a = 1; private b = 2; }\ndeclare const c: C, d: D;\nexport const { ...a: x } = c;\nexport const { ...a: b } = d;\nexport const sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "61-L17": { + "51-L20b": { "files": { - "a.js": "/** @overload */\nfunction () {}\n", - "b.js": "/**\n * @overload\n * @param {string} a\n * @overload\n * @param {number} a\n */\nfunction () {}\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "export class C { private a = 1; m(c: C) { const { ...a: x } = c; return x; } }\nexport class D { private a = 1; private x = 2; m(c: D) { const { ...a: x } = c; return x; } }\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" } }, - "62-L04a": { + "52-L01": { "files": { - "a.ts": "const k = \"foo\";\nclass C1 { get foo() { return 1 } set [k](v: number) {} }\nnew C1().foo = 2;\nclass C2 { static get foo() { return 1 } static set [k](v: number) {} }\nC2.foo = 2;\ninterface I3 { get foo(): number; set [k](v: number) }\ndeclare const i3: I3; i3.foo = 2;\ntype T4 = { get foo(): number; set [k](v: number) };\ndeclare const t4: T4; t4.foo = 2;\nclass C6 { set [k](v: number) {} get foo() { return 1 } }\nnew C6().foo = 2;\nclass C9 { get foo(): number { return 1 } set [k](v) {} }\nnew C9().foo = \"\";\ntype R1 = { [P in keyof C1]: C1[P] };\ndeclare const m1: R1; m1.foo = 1;\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "export {};\nfunction f({ ...a: b }: { x: number }): void;\nfunction f(x: any) {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2017\", \"importHelpers\": true, \"module\": \"esnext\" } }\n" } }, - "62-L06a": { + "52-L01b": { "files": { - "a.js": "const k = \"x\";\nclass D1 { static [k] = 1; static m() { this.x = 2; } }\nclass D2 { static m() { this.x = 2; } static [k] = 1; }\nclass D3 { constructor() { this.x = 2; } /** @readonly */ [k] = 1; }\nclass D4 { constructor() { this.x = 2; } /** @private */ [k] = 1; }\nclass D5 { constructor() { this.x = 2; } [k] = 1; }\n/** @type {number} */\nconst sentinel = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "export {};\ntype F = ({ ...rest }: { x: number }) => void;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2017\", \"importHelpers\": true, \"module\": \"esnext\" } }\n" } }, - "62-L07a": { + "52-L02": { "files": { - "a.ts": "declare const k10: I10[typeof k10b];\ndeclare const k10b: \"w\";\ninterface I10 { [k10]: 2; [k10b]: \"v\"; }\ndeclare const i: I10;\nconst p: boolean = i.w;\ntype T = I10[\"w\"];\ntype K = keyof I10;\nconst kk: K = \"w\";\nconst lit: I10 = { w: \"v\" };\nconst sentinel: number = \"\";\n", + "a.ts": "class K {}\ndeclare function f1({ a: b }: {}, c = b.x): void;\ndeclare function f2({ a: b }: {}, c = b()): void;\ndeclare function f3({ a: b }: {}, c = (b = 1)): void;\ndeclare function f4({ a: b }: {}, c = () => b): void;\ntype F5 = ({ a: b }: {}, c = b.x) => void;\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "62-L14": { + "52-L03": { "files": { - "a.ts": "declare const u: unknown; declare const a: {}; declare const c: boolean;\nlet e = {}; const { x, ...rest2 } = { x: 1 };\ntype I = { [k: string]: number };\nif (u) {\n const t1: I = c ? u : { ...a };\n const t2: I = c ? { ...a } : u;\n const t3: I[] = [u, { ...a }];\n const t4: I = c ? u : { ...{} };\n const t5: I = c ? u : { ...a, ...a };\n const t6: I = c ? u : { ...e };\n const t7: I = c ? u : { ...rest2 };\n}\nconst sentinel: number = \"\";\n", + "a.ts": "declare function f(a = nope): void;\nlet g: (x: number) => void;\ng = f;\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "63-L09": { + "52-L05": { "files": { - "a.js": "class C {\n constructor() {\n /** @type {ReturnType} */\n this.x = 1;\n }\n x = mk();\n}\nfunction mk() { return new C().x; }\nclass D {\n constructor() {\n this.y = mk2();\n }\n /** @type {ReturnType} */\n y;\n}\nfunction mk2() { return new D().y; }\n", - "b.ts": "new C().x();\nnew D().y();\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true }, \"files\": [\"a.js\", \"b.ts\"] }\n" + "a.ts": "declare const {} = miss1;\ndeclare const [] = miss2;\ndeclare let {} = miss3;\ndeclare const {}: {} = miss4;\ndeclare namespace N { const {} = miss5; }\ndeclare const {} = class { declare x = 1 };\ndeclare const {} = (() => { const q: number = \"\"; })();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "63-L18b": { + "52-L12": { "files": { - "a.ts": "import { x } from \"./café\";\nx;\nconst sentinel: number = \"\";\n", - "café.ts": "export const x = 1;\n", + "a.ts": "declare function g(x: number): number;\ndeclare class K { constructor(x: number); }\nfunction f1({ a = 1, b = g(a) }) { const s: string = a; }\nfunction f2({ a = 1, b = new K(a) }) {}\nfunction f3([a = 1, b = g(a)]) {}\nconst f4 = ({ a = 1, b = g(a) }) => {};\nclass C { m({ a = 1, b = g(a) }) {} }\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "71-R15a": { + "52-L13": { "files": { - "a.ts": "export {};\ntype Ctor = new (...a: any[]) => T;\nfunction h1(B: T & U) { return class extends B { static s = \"ok\"; }; }\nfunction h2(B: T & U) { return class extends B {}; }\nfunction h5(B: T & U) { return class extends B {}; }\nfunction h7(B: T & U) { return class extends B {}; }\nfunction h9(B: U & T) { return class extends B {}; }\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\" } }\n" + "a.ts": "declare function count(o: { A: number }): number;\nenum E { A = 1, B = count(E) }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "71-R15b": { + "52-L13b": { "files": { - "a.ts": "export {};\ntype Ctor = new (...a: any[]) => T;\nfunction g4(B: T & U) { return class extends B { static s = 1; }; }\nfunction g5(B: T & { s: string; f(): void }) { return class extends B { static s = 1; static f = 1; }; }\nfunction g7(B: T & { [k: string]: number }) { return class extends B { static s = \"x\"; }; }\nfunction h14(B: T & Record) { return class extends B {}; }\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\" } }\n" + "a.ts": "const k = \"kk\";\nfunction F() {}\nF[k] = { a: F.kk };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "52-L15": { + "files": { + "a.ts": "function next(e: E1) { return e + 1; }\nenum E1 { A = 1, B = next(E1.A) }\ndeclare function make(n: number): E2;\nenum E2 { A = 1, B = make(1) }\ndeclare const first: E3;\nenum E3 { A = 1, B = first }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "52-L15b": { + "files": { + "a.ts": "enum E1 { A = E1[\"z\"] } namespace E1 { export const z = 1; }\nenum E2 { A = E2[\"z\"] } namespace E2 { export function z() {} }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "52-L17": { + "files": { + "a.ts": "function entries(t: T) {\n if (t === null || t === undefined) return;\n for (const [k, v] of Object.entries(t)) v.foo;\n}\nfunction record(t: T) {\n if (t === undefined || t === null) return;\n const r: Record = t;\n}\nfunction both(t: T) { if (t === null) throw 0; if (t === undefined) throw 0; return t; }\nconst y = both(null! as unknown);\nconst r: { [k: string]: number } = y;\nconst { ...rest } = {}; const stays1: { [k: string]: number } = rest;\nconst spread = { ...{} }; const stays2: { [k: string]: number } = spread;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "52-L19": { + "files": { + "a.ts": "type Unk = unknown; type Nev = never;\nfunction f1() {}\nfunction f2() {}\nfunction f3() {}\nfunction f4() {}\nfunction f5() {}\nfunction f6() {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "53-L01b": { + "files": { + "a.ts": "enum F1 { [\"a\" as const] = 1, B = 2 }\nenum F2 { [\"a\"!] = 1, B = 2 }\nenum F3 { [\"a\" satisfies string] = 1, B = 2 }\nenum F4 { [\"a\"] = 1, B = 2 }\nenum F5 { [1 as const] = 1, B = 2 }\nenum F6 { [1!] = 1, B = 2 }\nconst k1: keyof typeof F1 = 0;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "53-L04": { + "files": { + "a.ts": "let x: any;\nlet s: string = \"\";\ndeclare const o: { \"1n\": number; a: number };\n({ 1n: x } = {});\n({ 1n: x } = [1, 2]);\n({ 1n: s } = o);\n({ 1n: { a: s } } = o);\n({ 1n: s = 1 } = o);\nfor ({ 1n: s } of [o]) {}\nclass P { private \"1n\" = 1; }\n({ 1n: s } = new P());\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "53-L04b": { + "files": { + "a.ts": "declare const o: { \"0x10n\": number; \"16n\": string; \"0xffn\": 1; \"255n\": 2 };\nconst { 0x10n: a } = o; const a1: never = a;\nconst { 0XFFn: c } = o; const c1: never = c;\nconst o1 = { 0b11n: 1, 3n: 2 };\nconst o2 = { 0XFFn: 1, 0xffn: 2 };\nconst o4 = { 0o7n: 1, \"7n\": 2 };\nconst o6 = { 0b11n: 1, \"0b11n\": 2 };\ndeclare function dec(t: any, c: { name: \"0xffn\" }): void;\ndeclare function dec2(t: any, c: { name: \"3n\" }): void;\nclass C { @dec 0XFFn() {} @dec2 0b11n() {} }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "53-L06": { + "files": { + "a.ts": "import { o } from \"./u\";\nexport const h = o;\nconst sentinel: number = \"\";\n", + "b.ts": "let v;\nv = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"declaration\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] }, \"files\": [\"a.ts\", \"b.ts\", \"u.ts\"] }\n", + "u.ts": "// @ts-nocheck\nexport const o = { g() { return v; } };\n" + } + }, + "53-L06b": { + "files": { + "a.ts": "import { o } from \"./u\";\nexport const h = o;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"declaration\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es5\"] }, \"files\": [\"a.ts\", \"u.ts\"] }\n", + "u.ts": "// @ts-nocheck\nexport const o = { *g() { yield 1; } };\n" + } + }, + "53-L06c": { + "files": { + "a.ts": "let v;\nv = 1;\nconst h = o;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"declaration\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] }, \"files\": [\"a.ts\", \"u.ts\"] }\n", + "u.ts": "// @ts-nocheck\nconst o = { g() { return v; } };\n" + } + }, + "53-L09b": { + "files": { + "a.ts": "import(\"./m\", { extra: (x) => {} });\nconst sentinel: number = \"\";\nexport {};\n", + "lib.d.ts": "interface Array { length: number } interface Boolean {} interface CallableFunction {} interface Function {} interface IArguments {} interface NewableFunction {} interface Number {} interface Object {} interface RegExp {} interface String {} interface Promise { then(): void } interface PromiseConstructor { new (f: any): Promise } declare var Promise: PromiseConstructor;\ntype ImportCallOptions = { extra?: (x: number) => void };\n", + "m.ts": "export {};\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"noLib\": true, \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "53-L14": { + "files": { + "a.ts": "declare class B {}\ndeclare class A2 extends B, (class { m() {} }) {}\ndeclare enum E4 { [(() => { return 1; })()] = 1 }\ndeclare namespace N11 { class K extends B extends (class { m() {} }) {} }\ndeclare namespace N12 { enum E { A = 1, [`x${(() => { return 1; })()}`] = 2 } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "53-L14b": { + "files": { + "a.ts": "declare function dec(...a: any[]): any;\n@dec(() => {}) declare class C1 {}\n@dec(function () {}) declare class C2 {}\n@dec({ m() {} }) declare class C3 {}\n@dec(class { m() {} }) declare class C4 {}\n@dec(() => {}) export declare class C5 {}\nexport @dec(() => {}) declare class C6 {}\n@dec(() => {}) declare abstract class C8 {}\n@dec(() => { let x = 1; return x; }) declare class C9 {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "53-L15": { + "files": { + "a.ts": "class D1 { declare p = async () => {}; }\nclass D3 { declare p = function () {}; }\nclass D4 { declare p = { m() {}, get g() { return 1; } }; }\nclass D5 { declare p = class { m() {} }; }\nclass D6 { declare static p = () => {}; }\nclass D7 { declare readonly p = () => { let x = 1; }; }\nclass D8 { declare [(() => { return \"a\" as const; })()]: number; }\nconst E13 = class { declare p = () => {}; };\nclass D14 { declare p = (a = () => {}) => {}; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "53-L16b": { + "files": { + "a.ts": "declare const dec: any;\nx = ({ @dec b }) => 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "53-L17": { + "files": { + "a.js": "const dec = 0, dec2 = 0;\n@dec export @dec2 function f1() {}\n@dec export @dec2 const x2 = 1;\n@dec export @dec2 async function f3() {}\n@dec export @dec2 class C4 {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "53-L17b": { + "files": { + "a.js": "const dec = 0;\nexport @dec default function f() {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "53-L18": { + "files": { + "a.ts": "const o1 = { readonly m() {} };\no1.m = () => {};\nconst p1: number = o1;\ntype M1 = { [K in keyof typeof o1]: (typeof o1)[K] };\ndeclare const m1: M1; m1.m = () => {};\nconst o4 = { readonly [\"m\"]() {} }; o4.m = null!;\nconst o7 = { readonly a: 1 }; o7.a = 2; const p7: string = o7;\ndelete o1.m;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "53-L20": { + "files": { + "a.js": "class B {} class C {}\n/** @augments B */\nclass A0 extends C {}\n/** @augments B */\nasync class A1 extends C {}\n/** @augments B */\nstatic class A2 extends C {}\n/** @augments B */\nexport export class A3 extends C {}\n/** @augments B */\naccessor class A4 extends C {}\n/** @extends B */\nasync class A5 extends C {}\n/** @augments B */\nexport async class A6 extends C {}\n/** @type {number} */ const sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "53-L20b": { + "files": { + "a.js": "class B {} class C {}\n/** @augments B */\nclass A1 extends C extends B {}\n/** @augments B */\nclass A2 extends C, B {}\n/** @type {number} */ const sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "53-L20c": { + "files": { + "a.ts": "class B {} class C {}\n/** @augments B */\nclass A0 extends C {}\n/** @augments B {@link C} */\nclass A1 extends C {}\n/**\n * @see C\n * @extends B\n */\nexport class A2 extends C {}\n/** {@link C} */\n/** @augments B */\nclass A3 extends C {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\" } }\n" + } + }, + "54-L01": { + "files": { + "a.ts": "import type D1, {} from \"./m\";\nexport {};\nconst sentinel: number = \"\";\n", + "m.ts": "export default class D {}\nexport const x = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\", \"importHelpers\": true, \"esModuleInterop\": true } }\n" + } + }, + "54-L02a": { + "files": { + "a.ts": "function h() { export { xxx as www }; www; }\nfunction h2() { export { yyy as vvv }; }\nfunction h3() { export { zzz }; zzz; }\nfunction h4() { const loc = 1; export { loc as uuu }; uuu; }\nfunction h5() { export { ttt as sss }; let q: sss; }\nfunction h6() { export { rrr as ppp }; let q: typeof ppp; }\nnamespace N { export { nnn as mmm }; mmm; }\n{ export { bbb as ccc }; ccc; }\nexport {};\nconst sentinel: number = \"\";\n", + "b.ts": "{ export { b1 as b2 }; }\n{ export { b3 as b4 }; b4; }\nfunction hb() { export { b5 as b6 }; b6; }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "54-L02b": { + "files": { + "a.ts": "declare module \"./t2\" { const v: number; }\nexport {};\nconst sentinel: number = \"\";\n", + "c.ts": "declare module \"./t2\" { type v3 = number; }\nexport {};\n", + "t2.d.ts": "declare const enum E { A } export = E;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "54-L02c": { + "files": { + "a.mts": "import t1 from \"x.json\";\nt1.amb; t1.k;\nconst sentinel: number = \"\";\n", + "amb.d.ts": "declare module \"x.json\" { const v: { amb: number }; export default v; }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"nodenext\", \"paths\": { \"x.json\": [\"./typed.json\"] } } }\n", + "typed.d.json.ts": "declare const v: { k: number };\nexport default v;\n" + } + }, + "54-L02d": { + "files": { + "a.mts": "import t1 from \"z\";\nimport { default as t2 } from \"z\";\nt1.amb; t2.amb;\nconst sentinel: number = \"\";\n", + "amb.d.json.ts": "declare module \"z\" { const v: { amb: number }; export default v; }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"nodenext\" } }\n" + } + }, + "54-L06": { + "files": { + "a.ts": "import { A1, A2, A3, A4, A5, A6, A7, A8, A9 } from \"./p\";\n/**\n * @typedef {Object} T\n * @property {string} a see {@link A1}\n */\nexport const s1 = 1;\n/** @callback F\n * @param {string} a see {@link A2}\n * @returns {string} see {@link A3}\n */\nexport const s2 = 1;\n/** @param {Object} o see {@link A4}\n * @param {string} o.a see {@link A5}\n * @param {string} b see {@link A6}\n */\nexport function s12(o: any, b: any) { return [o, b]; }\n/**\n * @overload\n * @param {string} a see {@link A7}\n * @returns {string} see {@link A8}\n */\n/**\n * @param {string} a see {@link A9}\n */\nexport function s13(a: any) { return a; }\nexport const sentinel: number = \"\";\n", + "b.js": "import { A1, A2, A3, A4, A5, A6, A7, A8, A9 } from \"./p\";\n/**\n * @typedef {Object} T\n * @property {string} a see {@link A1}\n */\n/** @callback F\n * @param {string} a see {@link A2}\n * @returns {string} see {@link A3}\n */\n/** @param {Object} o see {@link A4}\n * @param {string} o.a see {@link A5}\n * @param {string} b see {@link A6}\n */\nexport function s12(o, b) { return [o, b]; }\n/**\n * @overload\n * @param {string} a see {@link A7}\n * @returns {string} see {@link A8}\n */\n/**\n * @param {string} a see {@link A9}\n */\nexport function s13(a) { return a; }\n/** @type {number} */\nexport const sentinel = \"\";\n", + "p.ts": "export class A1 {} export class A2 {} export class A3 {} export class A4 {} export class A5 {} export class A6 {} export class A7 {} export class A8 {} export class A9 {}\nexport class B1 {} export class B2 {} export class B3 {} export class B4 {} export class B5 {} export class B6 {} export class B7 {} export class B8 {} export class B9 {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true, \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "54-L07a": { + "files": { + "a.ts": "import * as a from \"./m\";\nimport * as b from \"./m\";\nimport * as c from \"./m\";\nimport * as d from \"./m\";\nimport * as e from \"./m\";\nexport function f() {\n const a = 1;\n const b = 1;\n const c = 1;\n const d = 1;\n const e = 1;\n /** {@link a#delete} {@link b#foo} {@link c#default} {@link d#of} {@link e.delete} */\n const q = 2;\n return q;\n}\nexport const sentinel: number = \"\";\n", + "m.ts": "const x = 1;\nexport { x as delete, x as foo, x as default, x as of };\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "54-L07b": { + "files": { + "a.js": "/** Removes it, like {@link Map#delete}. See {@link Promise#catch} and {@link Map#get}. */\nexport const q1 = 2;\n/** {@link Map.} */\nexport const q2 = 2;\n/** {@link Map#} */\nexport const q3 = 2;\n/** @param {number} x {@linkcode Set#delete} {@linkplain Array#with} */\nexport function q4(x) { return x; }\n/** @type {number} */\nexport const sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "54-L08": { + "files": { + "a.ts": "import { A1, A2, A3, A4, A5, A6, A7, A8 } from \"./p\";\nexport type Range = [\n /** The start, see {@link A1} */\n start: number,\n /** {@link A2} */\n end?: number,\n /** {@link A3} */\n ...rest: string[],\n];\nexport function f(t: [\n /** {@link A4} */\n a: string,\n]) { return t; }\nexport type Unnamed = [\n /** {@link A5} */\n string,\n];\nexport type Same = [ /** {@link A6} */ a: string ];\nexport type Nested = { p: readonly [\n /** @see {@link A7} */\n a: string,\n] };\nexport type Generic = [\n /** {@link T} {@link A8} */\n a: T,\n];\nexport const sentinel: number = \"\";\n", + "p.ts": "export class A1 {} export class A2 {} export class A3 {} export class A4 {} export class A5 {} export class A6 {} export class A7 {} export class A8 {} export class A9 {}\nexport class B1 {} export class B2 {} export class B3 {} export class B4 {} export class B5 {} export class B6 {} export class B7 {} export class B8 {} export class B9 {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "54-L10": { + "files": { + "a.ts": "const o1 = { get a() { return 1 }, a: 2 };\no1.a();\nconst o2 = { a: 2, get a() { return 1 } };\no2.a();\nconst o3 = { set a(v: number) {}, get a() { return 1 } };\no3.a();\nconst o4 = { get a() { return 1 }, set a(v: number) {} };\no4.a();\nconst o5 = { get a() { return 1 }, a() {} , b: 1 };\no5.b();\nconst o6 = { set a(v: number) {}, a: 2 };\no6.a();\nconst k = \"a\";\nconst o7 = { get [k]() { return 1 }, [k]: 2 };\no7.a();\nconst o8 = { [k]: 2, get a() { return 1 } };\no8.a();\nconst o9 = { get a() { return 1 }, [k]: 2 };\no9.a();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "54-L11": { + "files": { + "a.ts": "const o1 = { a: 2, get a(): number { return 1 }, set a(v: string | number) {} };\no1.a = \"s\";\nconst o2 = { get a(): number { return 1 }, a: 2, set a(v: string | number) {} };\no2.a = \"s\";\nconst o3 = { get a(): number { return 1 }, set a(v: string | number) {}, a: 2 };\no3.a = \"s\";\nconst o4 = { get a(): number { return 1 }, set a(v: string | number) {} };\no4.a = \"s\";\nconst p1: boolean = o1;\nconst p2: boolean = o2;\nconst p3: boolean = o3;\nconst p4: boolean = o4;\nconst k = \"a\";\nconst o5 = { [k]: 2, get a(): number { return 1 }, set a(v: string | number) {} };\no5.a = \"s\";\nconst p5: boolean = o5;\nconst o6 = { a: 2, get [k](): number { return 1 }, set [k](v: string | number) {} };\no6.a = \"s\";\nconst p6: boolean = o6;\n({ a: o1.a } = { a: \"s\" });\nfor (o1.a of [\"s\"]) {}\no1.a += \"s\";\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "54-L11b": { + "files": { + "a.ts": "class C2 { get a(): number { return 1 } set a(v: string | number) {} a = 2; }\nnew C2().a = \"s\";\ndeclare const t1: { get a(): number; set a(v: string | number); a: number };\nt1.a = \"s\";\nconst p1: boolean = t1;\ninterface I2 { get a(): number; set a(v: string | number); a: number }\ndeclare const i2: I2;\ni2.a = \"s\";\nclass C1 { a = 2; get a(): number { return 1 } set a(v: string | number) {} }\nnew C1().a = \"s\";\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "54-L13": { + "files": { + "a.tsx": "namespace N {\n namespace React {\n export declare function createElement(...a: any[]): any;\n export namespace JSX {\n export interface Element {}\n export interface IntrinsicAttributes { key?: string }\n export interface IntrinsicClassAttributes { ref?: T }\n export interface IntrinsicElements { div: {} }\n }\n }\n function C(props: { x: string }) { return null as any; }\n export const e1 = ;\n export const e2 = ;\n export const e3 = ;\n class K { props!: { x: string }; constructor(p: { x: string }) {} render() { return null as any; } }\n export const e4 = ;\n export const e5 = ;\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"react\" } }\n" + } + }, + "54-L19": { + "files": { + "a.ts": "export {};\ndeclare function assert(c: unknown): asserts c;\nconst r = h(\"a\");\nfunction h(x: string) {\n if (typeof x !== \"string\") {\n assert(x === k);\n return x;\n }\n return 1;\n}\nconst k = r;\nconst sentinel: number = \"\";\n", + "b.ts": "export {};\ndeclare function assert(c: unknown): asserts c;\nconst r1 = h1(\"a\");\nfunction h1(x: string) {\n if (typeof x !== \"string\") { assert(x instanceof k1); return x; }\n return class {};\n}\nconst k1 = r1;\nconst r2 = h2(\"a\");\nfunction h2(x: string) {\n if (typeof x !== \"string\") { assert(k2 in x); return x; }\n return \"p\";\n}\nconst k2 = r2;\nconst r3 = h3(\"a\");\nfunction h3(x: string) {\n if (typeof x !== \"string\") { assert(x !== k3); return x; }\n return 1;\n}\nconst k3 = r3;\nconst r4 = h4(\"a\");\nfunction h4(x: string) {\n if (typeof x !== \"string\") { assert(true && x === k4); return x; }\n return 1;\n}\nconst k4 = r4;\nconst r5 = h5(null!);\nfunction h5(x: never) {\n assert(x === k5);\n return [x];\n}\nconst k5 = r5;\nconst r6 = h6(\"a\");\nfunction h6(x: string) {\n if (typeof x !== \"string\") { assert(!(x === k6)); return x; }\n return 1;\n}\nconst k6 = r6;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "54-L20a": { + "files": { + "a.ts": "export {};\ntype Action = { kind: 'A', payload: number } | { kind: 'B', payload: string };\nfunction f1({ kind, payload }?: Action) {\n if (kind === 'A') { const t: null = payload; }\n}\nfunction f2([kind, payload]?: ['A', number] | ['B', string]) {\n if (kind === 'A') { const t: null = payload; }\n}\nconst f3 = function ({ kind, payload }?: Action) {\n if (kind === 'A') { const t: null = payload; }\n};\nclass C { m({ kind, payload }?: Action) { if (kind === 'A') { const t: null = payload; } } }\nfunction f4({ kind, payload }?: Action | undefined) {\n if (kind === 'A') { const t: null = payload; }\n}\nfunction f5({ kind, payload }: Action | undefined) {\n if (kind === 'A') { const t: null = payload; }\n}\nconst sentinel: number = \"\";\n", + "b.js": "export {};\n/** @typedef {{ kind: 'A', payload: number } | { kind: 'B', payload: string }} Action */\n/** @param {Action} [p] */\nfunction f1({ kind, payload }) {\n if (kind === 'A') { /** @type {null} */ const t = payload; }\n}\n/** @param {Action=} p */\nfunction f2({ kind, payload }) {\n if (kind === 'A') { /** @type {null} */ const t = payload; }\n}\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "54-L20b": { + "files": { + "a.ts": "declare const cond: boolean;\nfunction g1({ kind, payload } = cond ? { kind: 'A' as const, payload: null } : { kind: 'B' as const, payload: 's' }) {\n if (kind === 'A') { const t: { x: 1 } = [payload]; payload.foo; }\n}\nfunction g4({ kind, payload } = cond ? { kind: 'A' as const, payload: [] } : { kind: 'B' as const, payload: 's' }) {\n if (kind === 'A') { const t: { x: 1 } = [payload]; payload.push(1); }\n}\nclass K { m({ kind, payload } = cond ? { kind: 'A' as const, payload: undefined } : { kind: 'B' as const, payload: 's' }) {\n if (kind === 'A') { const t: { x: 1 } = [payload]; }\n} }\nconst g5 = function ({ kind, payload } = cond ? { kind: 'A' as const, payload: null } : { kind: 'B' as const, payload: 's' }) {\n if (kind === 'A') { const t: { x: 1 } = [payload]; }\n};\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"strictNullChecks\": false, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L01": { + "files": { + "a.ts": "type Args = [a: 1, b: number] | [a: 2, b: string];\nconst g: (...args: Args) => void = (kind, x?) => {\n throw 0;\n x.toString();\n};\nfunction outer() {\n const h: (...args: A) => void = (kind, x) => {\n return;\n let y = x;\n y = true;\n };\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L03": { + "files": { + "a.ts": "declare function box(o: T): T;\ndeclare function both(o: T & { a: string | number }): T;\ndeclare function key(o: { key: K }): K;\nclass C {\n r!: string | number;\n m(x: this[\"r\"]) {\n let u = both({ a: x });\n u = 1;\n if (typeof x === \"string\") return;\n const n: number = box({ a: x }).a;\n let v = box({ a: x });\n v = 1;\n }\n n(name: keyof this) {\n let got = key({ key: name });\n got = 1;\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L04": { + "files": { + "a.ts": "declare function fail(): never;\nfunction f(o: any): number { with (fail()) { } }\nfunction g(o: any) { with (fail()) { } let x: string | number = 1; x.length; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowUnreachableCode\": false } }\n" + } + }, + "55-L06b": { + "files": { + "a.ts": "declare function g(a: unknown): number;\ndeclare class K { constructor(a: unknown); v: number }\nfunction h1({ a = 1, b = g(a) }) { return b; }\nconst h2 = ([a = 1, b = Math.max(a, 2)]) => b;\nclass C { m({ a = 1, b = new K(a) }) { return b; } }\n// not quick: TS7022 in both\nfunction h3({ a = 1, b = a + 1 }) { return b; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L08": { + "files": { + "a.ts": "type U = { kind: 0; a: string } | { kind: 1; b: number };\nfunction f1(x: U, v: 0 | 1) {\n if ((x.kind) = v) {\n x.b;\n } else {\n x.a;\n }\n if ((x[\"kind\"]) ||= v) {\n x.b;\n }\n}\n// without the parentheses both narrow\nfunction f2(x: U, v: 0 | 1) {\n if (x.kind = v) {\n x.b;\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L12a": { + "files": { + "a.ts": "const key = compute({ a: 1 }, {}, \"a\");\nfunction compute(o: { a: number }, p: any, i: \"a\") { p[key] = 1; return o[i]; }\nconst key2 = compute2({ a: 1 }, {}, \"a\");\nfunction compute2(o: { a: number }, p: any, i: \"a\") { if (p[key2]) {} return o[i]; }\nconst key3 = compute3({ a: 1 }, {});\nfunction compute3(o: { a: number }, p: any) { let i: \"a\" = \"a\"; p[key3] = 1; return o[i]; }\n// a key with a name: TS7023 in both\nconst key4 = compute4({ a: 1 }, {});\nfunction compute4(o: { a: number }, p: any) { const i = \"a\"; p[key4] = 1; return o[i]; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L12b": { + "files": { + "a.ts": "namespace NS { export let a = 1; }\nconst k1 = c1({});\nfunction c1(p: any) { if (p?.[k1].b) {} return (NS satisfies {})[\"a\"]; }\n// without `satisfies`: TS7023 in both\nconst k2 = c2({});\nfunction c2(p: any) { if (p?.[k2].b) {} return (NS)[\"a\"]; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L12c": { + "files": { + "a.ts": "const K: string = compute({ a: \"\" });\nfunction compute(o: Record) { return o[K]; }\nconst K3: string = compute3({ a: \"\" });\nfunction compute3(o: Record) { return o[K3].length + \"\"; }\n// an access on the way is compared with it: TS7023 in both\nconst K2: string = compute2({ a: \"\" });\nfunction compute2(o: Record) { o.x = \"\"; return o[K2]; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L12d": { + "files": { + "a.ts": "class C {\n static x: string | undefined;\n constructor() {\n if (new.other.x) { new.target.x.length; }\n if (new.target.x) { new.target.x.length; }\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L13": { + "files": { + "a.ts": "declare let a: number;\n({ a = 1 } += 1);\n[{ a = 1 }] += 1;\n({ x: { a = 1 } } += 1);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L16a": { + "files": { + "a.ts": "function mk(u: U, x: { k: 1 }) { return { u, ...x }; }\nconst a = mk(1, { k: 1 });\nconst b = mk(\"\", { k: 1 });\ndeclare function f(p: typeof b | T, q: T): T;\ndeclare const c: { u: number; k: 1; more: 1 };\nf(a, c);\nf(a, { z: 1 });\n// without the spread both agree\nfunction mk2(u: U) { return { u }; }\nconst a2 = mk2(1);\nconst b2 = mk2(\"\");\ndeclare function f2(p: typeof b2 | T, q: T): T;\ndeclare const c2: { u: number; more: 1 };\nf2(a2, c2);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L16b": { + "files": { + "a.ts": "import * as ns from \"./m\";\nimport fn = require(\"./m\");\ndeclare function f(p: typeof fn | T, q: T): T;\ndeclare const c: typeof ns & { more: 1 };\nf(ns, c);\nconst sentinel: number = \"\";\n", + "m.d.ts": "declare function fn(x: number): string;\ndeclare namespace fn { const extra: number }\nexport = fn;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"esModuleInterop\": true, \"module\": \"commonjs\" } }\n" + } + }, + "55-L18b": { + "files": { + "a.ts": "declare function one(v: T): { a: T; b: T };\nconst { a: [n, s], b = JSON.parse(\"[]\") } = one([1, \"hi\"]);\ns.length;\n// without the default of type `any` the pattern makes the argument a tuple in both\nconst { a: [n2, s2], b: b2 } = one([1, \"hi\"]);\ns2.length;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "55-L19": { + "files": { + "a.ts": "declare let n: null;\nfunction f1({ range: [lo, hi] = n || [0, 1] }) {}\nf1({ range: [1, 2, 3] });\nfunction f2([[a, b] = n ?? [1, \"x\"]]) {}\nf2([[\"x\", 1]]);\nlet z = f2;\nz = true;\n// without `??` the default is a tuple in both\nfunction f3([[a, b] = [1, \"x\"]]) {}\nf3([[\"x\", 1]]);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L01": { + "files": { + "a.js": "/** @template T */\nclass A { /** @type {T | undefined} */ x = undefined; }\n/** @augments {A<=} */\nclass B extends A {}\n/** @augments {A<<=} */\nclass C extends A {}\n/** @augments A<= */\nclass D extends A {}\n/** @implements {A<=} */\nclass E { x = undefined }\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "56-L02": { + "files": { + "a.ts": "type X = T extends [infer U \\u0065xtends string] ? U : never;\ntype Z = T extends infer U \\u0065xtends string ? U : never;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L05b": { + "files": { + "a.tsx": "const g = x => x;\nconst h = x, y;\nconst i = { a: 1 };\nconst j = (x: T) => x;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "56-L06": { + "files": { + "lt1.tsx": "class A {}\n", + "lt2.tsx": "function f() {}\n", + "lt3.tsx": "type X = 1\n", + "lt4.tsx": "interface I { (): void }\n", + "lt5.tsx": "let x: Array\n", + "lt6.tsx": "let x: [() {} }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "56-L07": { + "files": { + "a.ts": "export {};\ninterface M { m: T }\ndeclare const K: new () => {};\ntype U = 1;\nexport class C implements (M) {}\nexport interface X extends (M) {}\nexport class D implements K() {}\nexport interface Y extends M[0] {}\nexport class F implements (M), { a: typeof nope6 }> {}\nexport class G implements (M) {}\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "56-L08": { + "files": { + "a.ts": "declare const dec: any;\nconst f = (a: any, @dec x: any) => 1;\nconst g = (@dec x: T) => 1;\nconst h = (a: any, @dec() x?: any, @dec ...y: any[]) => 1;\nconst i = async (a: any, @dec x: any) => 1;\nconst j = (a = 1, @dec { b }: any) => 1;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L09": { + "files": { + "a.ts": "declare const v: any;\ninterface I {}\nclass X extends import, v {}\nclass Y implements import, {}\nclass Z implements I implements import, I {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L10": { + "files": { + "a.ts": "declare const x: any; declare const async: any; type U = 1;\nasync (x);\nasync (x);\nasync (x);\nasync (x: any);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L11": { + "files": { + "a.ts": "export {};\ndeclare const x: any;\nconst { [await]: a } = x;\ninterface I { [await]: 1 }\ninterface J { [await](): void; [await.x]: 1 }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L14": { + "files": { + "a.ts": "let a = 1 as const<>;\nlet a2 = >1;\nlet a3 = [1, \"x\"] as const<>;\nconst n: 2 = a;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L14b": { + "files": { + "a.ts": "declare const dec: any;\nasync function f() {\n let x: new (@await y: any) => void;\n let x2: abstract new (a: any, @await.b y: any) => void;\n let x3: (@await y: any) => void;\n let x4: { m(@await y: any): void; new (@await y: any): void };\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L14c": { + "files": { + "a.ts": "let x: ([...a,]: any);\nlet y: ({...a,}: any);\nlet z: ([...a,], b);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L15": { + "files": { + "a.ts": "declare const o: any;\no?.a`x`;\no?.a`x``y`;\no?.a`x`.b`y`;\no?.a`x${1}``y${2}`;\no?.a`x`()`y`;\no?.a`x`[0]`y`;\no?.a`x`!`y`;\n(o?.a`x`)`y`;\no?.a`x`.b.c;\no?.a`x``y`;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L17": { + "files": { + "a.ts": "export {};\ndeclare const p: Promise, q: Promise;\nconst o = { [await (p)]: await (q) };\nconst o2 = [await (q), { [await (p)]: 1 }];\nconst o3 = { [(await (p))]: await (q) };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"target\": \"es2022\" } }\n" + } + }, + "56-L19": { + "files": { + "a.ts": "type A = T extends infer #a ? 1 : 2;\ntype B = T extends [infer #a extends string] ? 1 : 2;\ndeclare function f(x: any): asserts #a;\ndeclare function g(x: any): asserts #a is string;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L20": { + "files": { + "a.ts": "declare class B {} declare class C {} declare class D {} interface I {} declare const a: any;\nclass A1 extends B, class extends C, D {} {}\nclass A2 implements I implements (class extends C, D {}) {}\nclass A3 extends B extends class extends C, D {} {}\nclass A4 extends B, class<> {} {}\nclass A5 implements (class extends C, D {}) {}\ninterface A6 extends I extends (class extends C, D {}) {}\ninterface A7 extends (class extends C, D {}) {}\npublic class A8 extends B, class extends C, D {} {}\nclass A9 extends B, (a?.b`x`) {}\nclass A10 extends B, (0 as I<>) {}\nclass A11 extends B, (a<>()) {}\nclass A12 extends B, (import) {}\nclass A13 extends B, ((x: I<1,>) => 1) {}\nclass A14 extends B, (function (p?, q) {}) {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "56-L20b": { + "files": { + "a.js": "/** @type {<>() => void} */\nlet a;\n/** @type {<>} */\nlet b;\n/** @type {Array<<>>} */\nlet c;\n/** @template T */\nclass A { /** @type {T | undefined} */ x = undefined; }\n/** @augments {A<<>} */\nclass E extends A {}\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "57-L01": { + "files": { + "a.ts": "declare const a: any, b: any;\n@a export export @b class C1 {}\n@a public export @b class C2 {}\n@a declare export @b class C3 {}\nfunction f() { @a export @b class C4 {} }\nnamespace N { export @a default class C5 {} }\nnamespace M { @a export default @b class C6 {} }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L02a": { + "files": { + "a.ts": "declare const a: any, b: any;\n@a default @b class C {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L02b": { + "files": { + "a.ts": "declare const dec: any;\n@dec interface = 1\n", + "b.ts": "@dec type\nT = 1\n", + "c.ts": "@dec namespace = 1\n", + "d.ts": "@dec module\nM = 1\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L02c": { + "files": { + "a.ts": "declare const dec: any;\n@dec export;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L02d": { + "files": { + "a.ts": "const \\u0065num E {}\n", + "b.ts": "export const \\u0065num E {}\n", + "c.ts": "declare const \\u0065num E {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L02f": { + "files": { + "a.ts": "declare const dec: any;\ntype A = 1;\nexport @dec type { A }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L03": { + "files": { + "a.ts": "let x: any;\n({ 1n: x } = {});\n[{ 1n: x }] = [{}];\nfor ({ 1n: x } of [{}]) {}\n({ a: { 1n: x } } = { a: {} });\n({ 1n: x = 3 } = {});\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L04": { + "files": { + "a.ts": "declare const o: any;\ndeclare class A {}\ninterface J {}\nclass C2 extends A<1>, A<{ 2n: 1 }> {}\ninterface I2 implements J<{ 1n: 1 }> {}\nclass C3 extends A<1> extends A<{ 1n: 1 }> {}\nclass C4 implements J<1> implements J<{ 1n: 1 }> {}\ninterface I3 extends J<1> extends J<{ 1n: 1 }> {}\nclass C5 extends A<1>, (class { 1n = 1 }) {}\nwith (o) { var v: { 1n: 1 }; var w = <{ 1n: 1 }>o; }\nv; w;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L04b": { + "files": { + "a.ts": "declare const o: any;\n{ export = o }\n{ export = missing2() }\nfunction f() { export = missing3() }\n{ export default missing4() }\nfunction g() { export default o }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L05": { + "files": { + "a.ts": "declare const o: any;\ninterface G {}\ndeclare function g(): void;\ndeclare class K {}\ntype X1 = G<(number | boolean)>;\ntype X2 = G<(() => void)>;\ng<(number)>();\nnew K<(number)>();\nclass L extends K<(number)> {}\ninterface M extends G<(number)> {}\ntype Y1 = { a: 1 }[(\"b\" | \"c\")];\ntype Y2 = { a: 1 }[(number)];\ntype Y3 = { a: 1 }[(boolean)];\ntype Y4 = [1, 2][(5)];\ntype M1 = { [K in (boolean)]: 1 };\ntype M2 = { [K in \"a\" as (boolean)]: 1 };\nfunction f1(): (ReturnType) { return o }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L13a": { + "files": { + "a.tsx": "interface Iterable {}\ndeclare namespace JSX { interface Element {} interface ElementChildrenAttribute { children: {} } interface IntrinsicElements {} }\ndeclare function C(props: { children: number }): JSX.Element;\ndeclare function D(props: { children: number[] }): JSX.Element;\ndeclare function E(props: { children: number | string[] }): JSX.Element;\nconst a1 = {\"x\"}{\"y\"};\nconst a2 = {\"x\"};\nconst a3 = {\"x\"}{\"y\"};\nconst a4 = {\"x\"};\nconst a5 = {true}{\"y\"};\nconst a6 = {true};\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es5\"], \"jsx\": \"preserve\" } }\n" + } + }, + "57-L13b": { + "files": { + "a.ts": "interface Array {} interface Boolean {} interface CallableFunction {} interface Function {} interface IArguments {} interface NewableFunction {} interface Number {} interface Object {} interface RegExp {} interface String {}\ninterface Promise {} interface PromiseConstructor {} declare var Promise: PromiseConstructor;\ninterface ImportCallOptions { with?: { f: (x: number) => void } }\nimport(\"./m\", { with: { f: x => {} } });\nconst sentinel: number = \"\";\n", + "m.ts": "export const m = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"noLib\": true, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "57-L13c": { + "files": { + "a.ts": "declare const i1: { a: 1 };\nfunction* g1() { yield* i1; }\nfunction* g2() { yield* [1]; }\nfunction* g3() { yield* \"\"; }\nasync function* g4() { yield* i1; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es5\"], \"target\": \"es2022\" } }\n" + } + }, + "57-L13d": { + "files": { + "a.ts": "interface Boolean {} interface CallableFunction {} interface Function {} interface IArguments {} interface NewableFunction {} interface Number {} interface Object {} interface RegExp {} interface String {}\ndeclare class Array { filter(f: (x: T) => x is S): S[]; filter(f: (x: T) => unknown): T[] }\ndeclare const u: string[] | number[];\nconst r1 = u.filter(x => true); const t1: 1 = r1;\ndeclare const v: readonly string[] | number[];\nconst r2 = v.filter(x => true); const t2: 1 = r2;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"noLib\": true } }\n" + } + }, + "57-L15": { + "files": { + "a.js": "function f() {}\nf.a = (f.a, exports);\nexports.b = 1;\n/** @type {number} */\nconst sentinel = \"\";\n", + "b.js": "class C {\n x = (new C().x, module);\n}\nexports.a = 1;\n", + "c.js": "class C {\n static x = (C.x, exports);\n}\nexports.a = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" } }\n" + } + }, + "57-L18": { + "files": { + "a.ts": "const f = async (x: T)\n", + "b.ts": "const g = async (x: T)\n", + "c.ts": "async (x);\n", + "d.ts": "async (x);\n", + "e.ts": "async (x);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "57-L18b": { + "files": { + "a.ts": "declare function async(x: T): T;\nasync (1);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "58-L01": { + "files": { + "a.ts": "class C3 { get x(this) { return 1 } set x(v) { this.nope; } }\nclass C4 { get x() { this.nope; return 1 } set x(this, v) { this.nope2 } }\nconst o4 = { get x() { this.nope; return 1 }, set x(this, v) { this.nope2 } };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "58-L03": { + "files": { + "a.ts": "declare const k: string; declare function fn(): string; declare const o: { p: string };\nfunction f1({ [1 + 2]: a }: any) {}\nfunction f2({ [fn( )]: a }: any) {}\nfunction f3({ [`a${ k }b`]: a }: any) {}\nfunction f4({ [o [ \"p\" ]]: a }: any) {}\nfunction f5({ [ /*c*/ k + /*d*/ \"x\" ]: a }: any) {}\nfunction f6({ [0x10 + 1]: a }: any) {}\nfunction f7({ [1\n + 2]: a }: any) {}\nconst n1: number = f1;\nconst n2: number = f2;\nconst n3: number = f3;\nconst n4: number = f4;\nconst n5: number = f5;\nconst n6: number = f6;\nconst n7: number = f7;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "58-L05": { + "files": { + "a.ts": "import { assertIsString, fail, Promise, Obj } from \"./real\";\nfunction t1(x: unknown) { assertIsString(x); x.length; }\nfunction t2(x: string | undefined) { if (!x) fail(); x.length; }\nfunction t3(): number { fail(); }\nfunction t4(x: unknown) { Obj.assert(x); x.length; }\nnew Promise(resolve => resolve());\nconst sentinel: number = \"\";\n", + "globals.d.ts": "declare function assertIsString(x: unknown): asserts x is string;\ndeclare function fail(): never;\ndeclare const Obj: { assert(x: unknown): asserts x is string };\n", + "real.ts": "namespace g2 {\n export interface assertIsString { t: 1 } export interface fail { t: 1 } export interface Promise { t: 1 } export interface Obj { t: 1 }\n}\nconst g2 = { v: 1 };\nexport = g2;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" } }\n" + } + }, + "58-L07a": { + "files": { + "a.ts": "import { S as S1 } from \"pkg/sub\";\nimport { get } from \"pkg\";\nimport { S as S2 } from \"other\";\ndeclare const s2: S2;\nconst s1: S1 = s2;\nconst s3: S2 = get();\nconst sentinel: number = \"\";\n", + "node_modules/other/index.d.ts": "export { S } from \"pkg/sub\";\n", + "node_modules/other/node_modules/pkg/package.json": "{ \"name\": \"pkg\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }\n", + "node_modules/other/node_modules/pkg/sub/index.d.ts": "export declare class S { private p: number; }\n", + "node_modules/other/node_modules/pkg/sub/package.json": "{ \"name\": \"pkg-sub\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }\n", + "node_modules/other/package.json": "{ \"name\": \"other\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }\n", + "node_modules/pkg/index.d.ts": "import { S } from \"./sub/index\"; export declare function get(): S;\n", + "node_modules/pkg/package.json": "{ \"name\": \"pkg\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }\n", + "node_modules/pkg/sub/index.d.ts": "export declare class S { private p: number; }\n", + "node_modules/pkg/sub/package.json": "{ \"name\": \"pkg-sub\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"a.ts\"] }\n" + } + }, + "58-L08b": { + "files": { + "aug.ts": "export {};\ndeclare module \"./m\" {\n export const c: number;\n export namespace d { const nd: number }\n export function f(): void;\n export class g {}\n export var h: number;\n export enum i { A }\n}\nconst sentinel: number = \"\";\n", + "m.js": "exports.c = 1;\nexports.d = 1;\nexports.f = 1;\nexports.g = 1;\nexports.h = 1;\nexports.i = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\" }, \"files\": [\"m.js\", \"aug.ts\"] }\n" + } + }, + "58-L09": { + "files": { + "a.ts": "import { N } from \"./m\";\nlet x1: N.Inner.Nope;\nlet x2: N.Nope;\nlet x3: N.Only1.Nope;\nlet x4: N.Inner.Deep.Nope;\nconst sentinel: number = \"\";\n", + "aug1.ts": "export {};\ndeclare module \"./m\" { namespace N { namespace Inner { interface A {} namespace Deep { interface A {} } } namespace Only1 { interface A {} } } }\n", + "aug2.ts": "export {};\ndeclare module \"./m\" { namespace N { namespace Inner { interface B {} namespace Deep { interface B {} } } } }\n", + "m.ts": "export namespace N { export const a = 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"m.ts\", \"aug1.ts\", \"aug2.ts\", \"a.ts\"] }\n" + } + }, + "58-L11a": { + "files": { + "__inferred type names__.ts": "export const c = 1; const inner: number = \"\";\n", + "a.ts": "import { c } from \"./__inferred type names__\";\nconst f: 0 = foo;\nconst g: 0 = c;\nconst sentinel: number = \"\";\n", + "node_modules/@types/foo/index.d.ts": "declare const foo: 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [\"foo\"], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"a.ts\"] }\n" + } + }, + "58-L11b": { + "files": { + "__inferred type names__.ts": "declare const c: 1; const inner: number = \"\";\n", + "a.ts": "/// \nconst f: 0 = foo;\nconst g: 0 = c;\nconst sentinel: number = \"\";\n", + "node_modules/@types/foo/index.d.ts": "declare const foo: 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [\"foo\"], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"a.ts\"] }\n" + } + }, + "58-L12": { + "files": { + "a.ts": "const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es5\"], \"libReplacement\": true, \"traceResolution\": true, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"a.ts\"] }\n" + } + }, + "58-L15a": { + "files": { + "a.ts": "const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true, \"jsx\": \"preserve\" }, \"files\": [\"x.TSX\", \"z.JSX\", \"a.ts\"] }\n", + "x.TSX": "declare namespace JSX { interface IntrinsicElements { div: { id?: string } } }\nconst el =
;\n", + "z.JSX": "const el2 =
;\n" + } + }, + "58-L15b": { + "files": { + "a.ts": "const sentinel: number = \"\";\n", + "m.MJS": "/** @type {number} */\nexport const mm = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"y.JS\", \"m.MJS\", \"a.ts\"] }\n", + "y.JS": "/** @type {number} */\nconst yy = \"\";\nfunction f(a) { return a; }\n" + } + }, + "58-L17": { + "files": { + "a.ts": "const o = 1; const v = \"\";\nnamespace N { export { v as o }; const t: boolean = o; }\nnamespace M { const w = true; export { w as o }; const t: null = o; function f() { const u: null = o; } }\nnamespace P { export { v as o }; export namespace Q { const t: null = o; } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "58-L20a": { + "files": { + "m.ts": "namespace obj { export interface p { t: 1 } }\nconst obj = { p: 1 };\nexport = obj;\n", + "mid.ts": "export { p } from \"./m\";\n", + "mid2.ts": "import { p } from \"./m\"; export { p as p3 };\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"module\": \"commonjs\", \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] }, \"files\": [\"m.ts\", \"mid.ts\", \"mid2.ts\", \"u.ts\"] }\n", + "u.ts": "import { p } from \"./m\";\nimport { p as p2 } from \"./mid\";\nimport * as mid from \"./mid\";\nimport { p3 } from \"./mid2\";\nconst v: string = p; let t: p = {};\nconst v2: string = p2; let t2: p2 = {};\nconst v3: string = mid.p; let t3: mid.p = {};\nconst v4: string = p3; let t4: p3 = {};\nconst sentinel: number = \"\";\n" + } + }, + "58-L20b": { + "files": { + "m.ts": "import { p } from \"./mid\";\nnamespace obj { export interface p { t: 1 } }\nconst obj = { p: 1, q: p };\nexport = obj;\nconst sentinel: number = \"\";\n", + "mid.ts": "export { p } from \"./m\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"module\": \"commonjs\", \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] }, \"files\": [\"m.ts\", \"mid.ts\"] }\n" + } + }, + "58-L20c": { + "files": { + "m.ts": "import { p } from \"./m\";\nnamespace obj { export interface p { t: 1 } }\nconst obj = { p: 1, q: p };\nexport = obj;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"module\": \"commonjs\", \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] }, \"files\": [\"m.ts\"] }\n" + } + }, + "59-L01a": { + "files": { + "a.ts": "type Digits = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7';\ntype T1 = `${Digits}${Digits}${Digits}${Digits}` | undefined;\ntype A = { a: string } | { b: number };\ntype B = { a: string } | { c: number };\ntype C = { a: string } | { d: number };\ntype D = { a: string } | { e: number };\ndeclare function g(x: { p: T1 | null }): void;\nfunction f(a: T1 & A, b: T1 & B, c: T1 & C, d: T1 & D, xs: (T1 | null)[], fn: () => T1 | null) {\n let x: { p: T1 | null } = { p: a };\n xs = [b];\n fn = () => c;\n g({ p: d });\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, + "59-L01b": { + "files": { + "a.ts": "type Digits = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7';\ntype T1 = `${Digits}${Digits}${Digits}${Digits}` | undefined;\ntype A = { a: string } | { b: number };\ntype B = { a: string } | { c: number };\nfunction f(x: T1 | null, a: T1 & A, b: T1 & B) {\n [x] = [a];\n ({ x } = { x: b });\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, + "59-L02": { + "files": { + "a.ts": "import j from \"./e.json\";\nconst m1: Record = j;\ndeclare function values(r: Record): T[];\nfunction f2(x: unknown, c: Function) {\n if (x instanceof c) {\n const m2: Record = x;\n const m3: { [k: string]: number } = x;\n const m4: Record = x;\n values(x);\n }\n}\nfunction f5(x: { a: 1 } | string, c: Function) {\n if (x instanceof c) {\n const m5: Record = x;\n }\n}\nconst { a, ...rest } = { a: 1 };\nconst m6: Record = rest;\nconst sentinel: number = \"\";\n", + "e.json": "", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"resolveJsonModule\": true, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "59-L06": { + "files": { + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"w*d/a.ts\"] }\n", + "w*d/a.ts": "import { x } from \"pkg/x\";\nimport { x as x2 } from \"pkg/dir/x.d.ts\";\nimport { y } from \"#i/y\";\nconst sentinel: number = \"\";\n", + "w*d/node_modules/pkg/lib/x.d.ts": "export const x: 1;\n", + "w*d/node_modules/pkg/package.json": "{ \"name\": \"pkg\", \"version\": \"1.0.0\", \"exports\": { \"./*\": \"./lib/*.d.ts\", \"./dir/\": \"./lib/\" } }\n", + "w*d/package.json": "{ \"name\": \"self\", \"imports\": { \"#i/*\": \"./src/*.ts\" } }\n", + "w*d/src/y.ts": "export const y = 1;\n" + } + }, + "59-L07": { + "files": { + "a.ts": "import css from \"sub/./x.css\";\nimport { j } from \"sub/./j\";\nimport { t } from \"sub/./t\";\nimport { d } from \"sub/./d\";\nimport { d as d2 } from \"sub/d\";\nimport css2 from \"sub/x.css\";\nconst sentinel: number = \"\";\n", + "modroot/sub/d.d.ts": "export const d: 1;\n", + "modroot/sub/j.js": "export const j = 1;\n", + "modroot/sub/t.tsx": "export const t = 1;\n", + "modroot/sub/x.d.css.ts": "declare const css: string; export default css;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"typeRoots\": [\"modroot\"] }, \"files\": [\"a.ts\"] }\n" + } + }, + "59-L09": { + "files": { + "a.b/c.ts": "export const c = 1;\n", + "b.mts": "import {} from \".\\\\x\";\nimport {} from \"./a.b\\\\c\";\nexport {};\n", + "sub/a.mts": "import {} from \"..\\\\x\";\nimport {} from \"../a.b\\\\c\";\nimport {} from \"..\\\\nothing\";\nimport {} from \"../x\\\\\";\nimport {} from \"../x\";\nimport {} from \"..\";\nimport {} from \".\";\nimport {} from \"../x/\";\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"node16\" } }\n", + "x.ts": "export const x = 1;\n" + } + }, + "59-L10": { + "files": { + "a.ts": "import { make, make2, make3 } from \"other\";\nexport const x = make();\nexport const x2 = make2();\nexport const x3 = make3();\nconst sentinel: number = \"\";\n", + "node_modules/dep/a.d.ts": "export interface Thing { a: number }\n", + "node_modules/dep/package.json": "{ \"name\": \"dep\", \"version\": \"1.0.0\", \"exports\": { \"./a\": \"./a.d.ts\", \"#x\": \"./x.d.ts\" } }\n", + "node_modules/dep2/a.d.ts": "export interface Thing2 { a: number }\n", + "node_modules/dep2/package.json": "{ \"name\": \"dep2\", \"version\": \"1.0.0\", \"exports\": { \"\": \"./x.d.ts\", \"./a\": \"./a.d.ts\" } }\n", + "node_modules/dep3/a.d.ts": "export interface Thing3 { a: number }\n", + "node_modules/dep3/package.json": "{ \"name\": \"dep3\", \"version\": \"1.0.0\", \"exports\": { \"./a\": \"./a.d.ts\" } }\n", + "node_modules/other/index.d.ts": "import { Thing } from \"dep/a\";\nimport { Thing2 } from \"dep2/a\";\nimport { Thing3 } from \"dep3/a\";\nexport declare function make(): Thing;\nexport declare function make2(): Thing2;\nexport declare function make3(): Thing3;\n", + "node_modules/other/package.json": "{ \"name\": \"other\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }\n", + "out/a.d.ts": "export declare const x: import(\"dep/a\").Thing;\nexport declare const x2: import(\"dep2/a\").Thing2;\nexport declare const x3: import(\"dep3/a\").Thing3;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"declaration\": true, \"emitDeclarationOnly\": true, \"outDir\": \"out\", \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"a.ts\"] }\n" + } + }, + "59-L18": { + "files": { + "a.ts": "const k = \"k\";\nconst j = \"j\";\ntype T1 = { get k(); set [k](v: string) };\ntype T2 = { set [k](v: string); get k() };\ntype T3 = { set k(v); get [k](): string };\ntype T4 = { get [k](): string; set k(v) };\nfunction f(p: { get k(); set [k](v: string) }) {}\n// The members are resolved before the type literal is checked, or by an earlier late-bound member.\nlet before: T5[\"k\"];\ntype T5 = { get k(); set [k](v: string) };\ntype T6 = { get k(); set [k](v: string); get j(); set [j](v: string) };\n// `checkIndexConstraints` resolves the members of these before they are checked.\ninterface I1 { get k(); set [k](v: string) }\ndeclare class C1 { get k(); set [k](v: string) }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "59-L19a": { + "files": { + "a.ts": "class Base { value?: T; other!: T; n?: number; init: T | undefined = undefined; }\ntype Ctor = new (...a: any[]) => T;\nfunction MixAny>>(B: TB) { return class extends B { extra = 1 }; }\nfunction MixUnknown>>(B: TB) { return class extends B {}; }\nfunction MixSame>>(B: TB) { return class extends B {}; }\nclass D1 extends MixAny(Base) {}\nclass Num extends Base {}\nclass D2 extends MixAny(Num) {}\nclass D3 extends MixUnknown(Base) {}\nclass D4 extends MixSame(Base) {}\nclass D5 extends MixAny(Base) { value?: number }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\" } }\n" + } + }, + "59-L19b": { + "files": { + "a.ts": "abstract class A { abstract m(): void; abstract p: number; abstract h: T; abstract o: { a: 1 }; abstract arr: number[]; }\nfunction mixN A>(B: T) { abstract class M extends B {} return M; }\nfunction mixA A>(B: T) { abstract class M extends B {} return M; }\nclass N1 extends mixN(A) {}\nclass A1 extends mixA(A) {}\nclass AA extends mixA(A) {}\nabstract class A2 { abstract m(): void; }\nfunction mix2 A2>(B: T) { abstract class M extends B {} return M; }\nclass E2 extends mix2(A2) {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "59-L20": { + "files": { + "a.ts": "const g1 = () => {}; g1.a = \"b\" as const; g1[k1] = 1; declare const k1: (typeof g1)[\"a\"];\nconst g2 = function () {}; g2.a = \"b\" as const; g2[k2] = 1; declare const k2: (typeof g2)[\"a\"];\nfunction g3() {} g3.a = \"b\" as const; g3[k3] = 1; declare const k3: (typeof g3)[\"a\"];\ndeclare const k4: (typeof g4)[\"a\"]; const g4 = () => {}; g4.a = \"b\" as const; g4[k4] = 1;\nconst g5 = () => {}; g5.a = \"b\" as const; g5[k5] = 1; const k5 = \"c\"; g5.c;\nconst g6 = () => {}; g6.a = \"b\" as const; g6[k6] = 1; declare const k6: \"c\"; g6.c; g6.b;\nconst g7 = () => {}; g7[k7] = 1; declare const k7: ReturnType extends void ? \"c\" : \"d\"; g7.c;\nconst g8 = () => {}; g8.a = \"b\" as const; declare const k8: (typeof g8)[\"a\"]; g8[k8] = 1; g8.b;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L02": { + "files": { + "a.ts": "export function f(this, a: number): void {}\nexport const g = function (this, a: number): void {};\nexport class A { m(this, v: number): void {} static n(this): void {} }\nexport interface I { m(this, v: number): void; (this): void; }\nexport type T = (this, a: number) => void;\nexport const o = { m(this, a: number): void {} };\nexport function h(b, a: number): void {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noImplicitAny\": false, \"declaration\": true, \"isolatedDeclarations\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L04a": { + "files": { + "a.js": "function f() { const s = Symbol(); return { [s]: 1 }; }\nexport class C0 { constructor() { this.x = f(); } }\nexport class C1 { [+1]() {} constructor() { this[1] = f(); } }\nexport class C2 { 1() {} constructor() { this[1] = f(); } }\nexport class C3 { [1]() {} constructor() { this[1] = f(); } }\nexport class C4 { [-1]() {} constructor() { this[\"-1\"] = f(); } }\nexport class C5 { [+1]() {} constructor() { this[\"+1\"] = f(); } }\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"declaration\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L04b": { + "files": { + "a.ts": "function f() { const s = Symbol(); return { [s]: 1 }; }\nexport function g() {}\ng[\"ab\"] = f();\ng.cd = f();\ng[1] = f();\nexport const h = () => {};\nh[\"ab\"] = f();\nh.cd = f();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"declaration\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L05": { + "files": { + "a.ts": "class A1 { [+2]: number; constructor() { this[\"+2\"] = 1; } }\nclass B5 { [-2]: number; constructor() { this[\"-2\"] = 1; } }\nclass B4 { [-2]: number; constructor() { this[-2] = 1; } }\nclass A4 { [2]: number; constructor() { this[2] = 1; } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L06": { + "files": { + "a.ts": "class A1 { [+2] = 1; }\nconst m1: null = null! as keyof A1;\ninterface I2 { [+2]: 1; [-0]: 2; [-3]: 3 }\nconst m2: null = null! as keyof I2;\ntype T3 = { [+2]: 1 };\nconst m3: null = null! as keyof T3;\nconst o4 = { [+2]: 1 };\nconst m4: null = null! as keyof typeof o4;\ntype M5 = { [K in keyof I2]: K }; const m5: null = null! as M5;\ndeclare const a1: A1; a1[2]; a1[\"+2\"]; a1[\"2\"];\ndeclare const i2: I2; i2[2]; i2[\"+2\"]; i2[0]; i2[\"-0\"]; i2[-0]; i2[-3]; i2[\"-3\"];\ntype P6 = Pick; type P7 = Pick; type P8 = I2[2]; type P9 = I2[\"+2\"];\nconst k10: keyof I2 = 2; const k11: keyof I2 = \"+2\"; const k12: keyof I2 = 0; const k13: keyof I2 = \"-0\";\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L16a": { + "files": { + "a.ts": "interface Asserts { str(x: unknown): asserts x is string; num: (x: unknown) => asserts x is number }\ntype Prefixed = { [K in keyof T as `assert${Capitalize}`]: T[K] };\ndeclare const p: Prefixed;\nfunction f(v: unknown, w: unknown) {\n p.assertStr(v);\n v.length;\n p.assertNum(w);\n w.toFixed();\n}\nconst inferred = { bad: (x: unknown): asserts x is string => {} };\ndeclare const q: Prefixed;\nfunction g(v: unknown) { q.assertBad(v); }\nconst sentinel: number = \"\";\n", + "bun.related.txt": "a.ts(5,3) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(6,3) TS18046 'v' is of type 'unknown'.\na.ts(7,3) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(8,3) TS18046 'w' is of type 'unknown'.\na.ts(12,26) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(13,7) TS2322 Type 'string' is not assignable to type 'number'.\n", + "tsc.related.txt": "a.ts(12,26) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\n related a.ts(10,20) 'bad' needs an explicit type annotation.\na.ts(13,7) TS2322 Type 'string' is not assignable to type 'number'.\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L16b": { + "files": { + "a.ts": "type A = (x: unknown) => asserts x is string;\nconst inferred = (x: unknown): asserts x is string => {};\nconst obj = { a: inferred, m(x: unknown): asserts x is string {} };\ndeclare const v: unknown;\ninterface I { a: A; m(x: unknown): asserts x is string }\ntype Id = { [K in keyof T]: T[K] };\ndeclare const x1: Id<{ a: A } & typeof obj>; x1.a(v);\ndeclare const x2: Id; x2.a(v);\ndeclare const x3: Id<{ a: A } & { a: A }>; x3.a(v);\ndeclare const x4: Id; x4.a(v); x4.m(v);\ndeclare const x5: Id; x5.a(v);\ndeclare const x6: Id<{ a: A } | { a: A }>; x6.a(v);\ndeclare const x7: Id>; x7.a(v); x7.m(v);\ndeclare const x8: Id>; x8.a(v); x8.m(v);\ndeclare const x9: Id<{ m(x: unknown): asserts x is string } & { m: A }>; x9.m(v);\ndeclare const y1: Id<{ m: A } & { m(x: unknown): asserts x is string }>; y1.m(v);\ndeclare const y2: Id<{ a: A } & { a: (x: unknown) => asserts x is string }>; y2.a(v);\ndeclare const y3: { a: A } & { a: (x: unknown) => asserts x is string }; y3.a(v);\nconst sentinel: number = \"\";\n", + "bun.related.txt": "a.ts(8,46) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\n related a.ts(3,15) 'a' needs an explicit type annotation.\na.ts(12,44) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(14,39) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\n related a.ts(3,15) 'a' needs an explicit type annotation.\na.ts(18,74) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(19,7) TS2322 Type 'string' is not assignable to type 'number'.\n", + "tsc.related.txt": "a.ts(7,46) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(8,46) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(9,44) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(12,44) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(14,39) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\n related a.ts(3,15) 'a' needs an explicit type annotation.\na.ts(15,74) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(16,74) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(17,78) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(18,74) TS2775 Assertions require every name in the call target to be declared with an explicit type anno\na.ts(19,7) TS2322 Type 'string' is not assignable to type 'number'.\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L17": { + "files": { + "a.ts": "class C { private constructor() {} x = 1; }\ntype CT = typeof C;\ninterface IC extends CT {}\ndeclare const B1: IC;\nclass D1 extends B1 {}\ninterface IC6 extends IC { y: 1 }\ndeclare const B6: IC6;\nclass D6 extends B6 {}\nclass D2 extends C {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L19a": { + "files": { + "a.ts": "declare class G1 { static get prototype(): number; }\nconst a1: number = G1.prototype;\ndeclare class G2 { static set prototype(v: number); }\nG2.prototype = 1; G2.prototype = new G2();\ndeclare class G4 { static accessor prototype: number; }\nconst a5: number = G4.prototype;\nconst s1 = { ...G1 }; const a14: null = s1;\nclass C4 { static get prototype() { return 1; } }\nconst p4: null = C4.prototype;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L19b": { + "files": { + "a.ts": "declare class G6 { static readonly prototype: G6; }\nG6.prototype = new G6();\ndeclare class G7 { private static prototype: G7; }\nG7.prototype;\ntype K7 = keyof typeof G7; const a13: null = null! as K7;\ndeclare class G9 { protected static prototype: G9; }\nG9.prototype;\ndeclare class G5 { static prototype: G5; }\nG5.prototype = new G5();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L20a": { + "files": { + "a.ts": "const k = \"foo\";\nclass C1 { get foo() { return 1; } set [k](v: number) {} }\nnew C1().foo = 2;\nclass C3 { static get foo() { return 1; } static set [k](v: number) {} }\nC3.foo = 2;\nclass C6 { set [k](v: number) {} get foo() { return 1; } }\nnew C6().foo = 2;\ndeclare const v5: { get foo(): 1; set [k](v: 2) }; v5.foo = 2;\ninterface I7 { get foo(): 1; set [k](v: 2) } declare const i7: I7; i7.foo = 2;\ndeclare const v7: { foo: number; get [k](): string }; const n7: null = v7; v7.foo = \"\";\nclass C2 { get [k]() { return 1; } set foo(v: number) {} }\nnew C2().foo = 2;\nclass C8 { get [k]() { return 1; } set [k](v: number) {} }\nnew C8().foo = 2;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L20b": { + "files": { + "a.ts": "function f() { const s = Symbol(); return { [s]: 1 }; }\nconst k = \"foo\";\nexport class H1 { get foo() { return f(); } set [k](v) {} }\nexport class H2 { get [k]() { return f(); } set foo(v) {} }\nexport class H3 { get [k]() { return f(); } set [k](v) {} }\nexport class H4 { set [k](v) {} get foo() { return f(); } }\nexport class H5 { static get foo() { return f(); } static set [k](v) {} }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"declaration\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "60-L20c": { + "files": { + "a.js": "const k = \"foo\";\nclass D3 { static [k] = 1; static { this.foo = 2; } }\nclass D4 { static [k] = 1; static m() { this.foo = 2; } }\nclass D5 { [k] = 1; constructor() { this.foo = 2; } }\nclass D6 { [k] = 1; m() { this.foo = 2; } }\nclass D7 { static foo = 1; static { this.foo = 2; } }\nclass D8 { static [k]; static { this.foo = 2; } }\nclass D9 { static { this.foo = 2; } static [k] = 1; }\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L02": { + "files": { + "a.ts": "export {};\ndeclare const arr: any[];\ndeclare const o: { p: any };\nfunction b1(p: string) { [...x1, arr[0]] = arr; p; }\nfunction b2(p: string) { ({ ...x2, p: o.p } = o); p; }\nfunction b3(p: string) { [...x3 = 1] = arr; p; }\nfunction b4(p: string) { [...x4, arr[0]] = arr; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L02b": { + "files": { + "a.ts": "export {};\ndeclare const arr: any[];\nfunction a1() { let q: number | undefined; q; [...x1, arr[0]] = arr; }\nfunction a2() { [...x2, arr[0]] = arr; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L03": { + "files": { + "a.ts": "export {};\ndeclare let on: { n: number; m(): void };\ndeclare function f(): \"m\";\n({ [r1]() {} } = on);\n({ get [r2]() { return 1; } } = on);\n({ [f(1)]() {} } = on);\n({ [r3]() {} } = { m() {} });\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L04": { + "files": { + "a.ts": "export const o1 = { m(this, a: number): void {} };\nexport const f1 = function (this, a: number): void {};\nexport function g1(this, a: number): void {}\nexport class C { m(this, a: number): void {} }\nexport interface I { m(this, a: number): void }\nexport const f2 = function (this: string, a: number): void {};\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"declaration\": true, \"isolatedDeclarations\": true } }\n" + } + }, + "61-L04b": { + "files": { + "a.ts": "export const o3 = { get y(): number { return 1; }, set y(this: any) {} };\nexport const o2 = { get x(): number { return 1; }, set x(this: any, v: number) {} };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"declaration\": true, \"isolatedDeclarations\": true } }\n" + } + }, + "61-L05": { + "files": { + "a.tsx": "export const a =
;\nexport const b =
;\nconst sentinel: number = \"\";\n", + "node_modules/pre/jsx-runtime.d.ts": "export namespace JSX { interface IntrinsicElements { div: {} } interface Element {} } export function jsx(): void;\n", + "node_modules/pre/package.json": "{ \"name\": \"pre\", \"version\": \"1.0.0\", \"type\": \"module\", \"exports\": { \"./jsx-runtime\": { \"types\": \"./jsx-runtime.d.ts\", \"default\": \"./jsx-runtime.js\" } } }\n", + "package.json": "{ \"name\": \"app\" }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"react-jsx\", \"jsxImportSource\": \"pre\", \"module\": \"node16\" } }\n" + } + }, + "61-L05b": { + "files": { + "a.tsx": "export const a =
;\nexport const b =
;\nconst sentinel: number = \"\";\n", + "node_modules/@types/react/jsx-runtime.d.ts": "export namespace JSX { interface IntrinsicElements { div: {} } interface Element {} } export function jsx(): void;\n", + "node_modules/@types/react/package.json": "{ \"name\": \"@types/react\", \"version\": \"1.0.0\" }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"react-jsx\", \"jsxImportSource\": \"@types/react\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "61-L05c": { + "files": { + "a.tsx": "export const a =
;\nexport const b =
;\nconst sentinel: number = \"\";\n", + "package.json": "{ \"type\": \"module\" }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"react-jsx\", \"jsxImportSource\": \"./x\", \"module\": \"nodenext\" } }\n", + "x/jsx-runtime.ts": "export namespace JSX { export interface IntrinsicElements { div: {} } export interface Element {} } export function jsx(): void {}\n" + } + }, + "61-L06": { + "files": { + "a.ts": "declare function f1({ a: \\u0062 }: any): void;\ntype T7 = ({ a: \\u{62}c }: any) => void;\ntype T8 = ({ \\u0061: b }: any) => void;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L08": { + "files": { + "a.ts": "export const a = f();\nexport async function g() {}\nfunction f() { return C.get(new C()); }\nclass C { #x = 1; static get(c: C) { return c.#x; } }\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"target\": \"es2015\", \"lib\": [\"es2022\"], \"importHelpers\": true, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "61-L09": { + "files": { + "a.ts": "declare namespace N { const o: { get a() {} } }\ndeclare namespace N3 { type U = { get a() { let x = 1; return x; } } }\ndeclare const p: { set a(v: number) {} };\nconst q: { get a() { return 1; } } = { a: 1 };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L12": { + "files": { + "a.ts": "export {};\nimport.defer?.(\"./nope\");\nimport.defer?.(\"./nope\");\nconst x1: number = import.defer?.(\"./b\");\nconst x2: number = import.defer(\"./b\");\nconst sentinel: number = \"\";\n", + "b.ts": "export const b = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "61-L14": { + "files": { + "a.ts": "@dec namespace class {}\n", + "b.ts": "@dec interface class {}\n", + "c.ts": "@dec type class = 1\n", + "d.ts": "@dec namespace\nN {}\n", + "e.ts": "@dec interface\nI {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L15b": { + "files": { + "a.ts": "export {};\ninterface I { default class: 1 } declare const i: I; i.class; i.default;\ntype T = { default function: 1 }; declare const t: T; t.function; t.default;\nclass C { default class = 1 } declare const c: C; c.class; c.default;\ninterface L { default class: 1; default: 2 }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L16": { + "files": { + "p001.ts": "interface I { \\u0065xport z: 1 }\n", + "p002.ts": "interface I { \\u0069n z: 1 }\n", + "p003.ts": "interface I { d\\u0065fault class: 1 }\n", + "p004.ts": "interface I { readonly \\u0065xport z: 1 }\n", + "p005.ts": "type T = { \\u0065xport z: 1 }\n", + "p006.ts": "interface I { \\u0065xport [k: string]: 1 }\n", + "p007.ts": "class C { \\u0065xport z = 1 }\n", + "p008.ts": "class C { \\u0063onst z = 1 }\n", + "p009.ts": "function f(\\u0065xport z: number) {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L17": { + "files": { + "a.js": "/** @overload */\nfunction () {}\n", + "b.js": "/**\n * @overload\n * @param {string} a\n * @overload\n * @param {number} a\n */\nfunction () {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L17b": { + "files": { + "a.js": "function f() => 1\n", + "b.js": "function 1() {}\n", + "c.js": "class C { m() 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "61-L20": { + "files": { + "a.ts": "export {};\ninterface Tree { children: Tree[] }\nlet root: Tree | undefined;\nfunction getRoot() { return root ??= build() as Tree; }\nfunction build() { return { children: [getRoot()] }; }\nlet x: number;\nfunction g1() { return x = g1() as number; }\nfunction g6() { return [x = g6() as number]; }\nfunction g10() { x = g10() as number; return x; }\nfunction f4() { const r = f4() as number; return r; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L01": { + "files": { + "a.ts": "type X = [...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A];\nconst x1 = f1();\nconst x2 = new C2();\nasync function g() {\n const x3 = await f3();\n const x4 = await (0 as any as X>>>);\n}\nfunction h(p = f5()) {}\nclass K { q = f6(); }\nconst { a = f7() } = {} as { a?: number };\nconst x9 = (f9());\ndeclare function f1(): X>>>;\ndeclare const C2: new () => X>>>;\ndeclare function f3(): X>>>;\ndeclare function f5(): X>>>;\ndeclare function f6(): X>>>;\ndeclare function f7(): X>>>;\ndeclare function f9(): X>>>;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L02a": { + "files": { + "a.ts": "type X = [...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A];\nconst g7: { m: F7 } = { m() { return 1; } };\nconst g8: { a: 1, m: F8 } = { a: 1, async m() { return 1; } };\nlet g9: { m: F9 };\ng9 = { [\"m\"]() { return 1; } };\ntake({ m() { return 1; } });\ndeclare function take(o: { m: F10 }): void;\ntype F7 = () => X>>>;\ntype F8 = () => X>>>;\ntype F9 = () => X>>>;\ntype F10 = () => X>>>;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L02b": { + "files": { + "a.ts": "type X = [...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A];\ntake1(function named(x) {});\ntake2((x) => {});\ndeclare let o: I3;\no.m = function named3(x) {};\no.n = function (x) {};\no.k = (x) => {};\nconst o8: { m: F8 } = { m: function (x) {} };\ndeclare function take1(cb: (x: X>>>) => void): void;\ndeclare function take2(cb: (x: X>>>) => void): void;\ninterface I3 { m(x: X>>>): void; n(x: X>>>): void; k(x: X>>>): void }\ntype F8 = (x: X>>>) => void;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L03a": { + "files": { + "a.ts": "declare let a: number; declare let b: number;\n({ a = 1 } += 1);\n({ a: b = 1 } += 1);\n[{ a = 1 }] += 1;\n({ a = 1, ...{} } += 1);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L04a": { + "files": { + "a.ts": "const k = \"foo\";\nclass C1 { get foo() { return 1 } set [k](v: number) {} }\nnew C1().foo = 2;\nclass C2 { static get foo() { return 1 } static set [k](v: number) {} }\nC2.foo = 2;\ninterface I3 { get foo(): number; set [k](v: number) }\ndeclare const i3: I3; i3.foo = 2;\ntype T4 = { get foo(): number; set [k](v: number) };\ndeclare const t4: T4; t4.foo = 2;\nclass C6 { set [k](v: number) {} get foo() { return 1 } }\nnew C6().foo = 2;\nclass C9 { get foo(): number { return 1 } set [k](v) {} }\nnew C9().foo = \"\";\ntype R1 = { [P in keyof C1]: C1[P] };\ndeclare const m1: R1; m1.foo = 1;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L06a": { + "files": { + "a.js": "const k = \"x\";\nclass D1 { static [k] = 1; static m() { this.x = 2; } }\nclass D2 { static m() { this.x = 2; } static [k] = 1; }\nclass D3 { constructor() { this.x = 2; } /** @readonly */ [k] = 1; }\nclass D4 { constructor() { this.x = 2; } /** @private */ [k] = 1; }\nclass D5 { constructor() { this.x = 2; } [k] = 1; }\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L06b": { + "files": { + "a.js": "const k = \"x\";\nconst o = { [k]: 1, m() { this.x = 2; } };\n/** @type {boolean} */ const a = o;\nconst o2 = { [k]: 1, n: 1, get g() { this.x = 2; return 1; } };\n/** @type {boolean} */ const d = o2;\n/** @type {{ m(): void, x: string, n: string }} */ const e = o2;\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L07a": { + "files": { + "a.ts": "declare const k10: I10[typeof k10b];\ndeclare const k10b: \"w\";\ninterface I10 { [k10]: 2; [k10b]: \"v\"; }\ndeclare const i: I10;\nconst p: boolean = i.w;\ntype T = I10[\"w\"];\ntype K = keyof I10;\nconst kk: K = \"w\";\nconst lit: I10 = { w: \"v\" };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L12": { + "files": { + "a.ts": "declare const dec: any; class A {} class B {}\n@dec export default @dec class<> extends A, B {}\nnamespace N { export default class<> extends A, B {} }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L13a": { + "files": { + "a.ts": "import D from \"./a\";\ndeclare const dec: any;\ndeclare class Base { }\ninterface Base extends D {}\n@dec export default class extends Base {}\nconst sentinel: number = \"\";\n", + "b.ts": "import D from \"./b\";\ndeclare const dec: any;\n@dec export default class extends D {}\n", + "c.ts": "declare const dec: any;\n@dec export default class { a = 1 }\n", + "d.ts": "import \"./c\";\ndeclare module \"./c\" { export default class { b: number } }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "62-L13b": { + "files": { + "a.ts": "export default class { a!: T }\nexport default interface I { b: U }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L14": { + "files": { + "a.ts": "declare const u: unknown; declare const a: {}; declare const c: boolean;\nlet e = {}; const { x, ...rest2 } = { x: 1 };\ntype I = { [k: string]: number };\nif (u) {\n const t1: I = c ? u : { ...a };\n const t2: I = c ? { ...a } : u;\n const t3: I[] = [u, { ...a }];\n const t4: I = c ? u : { ...{} };\n const t5: I = c ? u : { ...a, ...a };\n const t6: I = c ? u : { ...e };\n const t7: I = c ? u : { ...rest2 };\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L15": { + "files": { + "a.ts": "const a1 = { m() { return this.z; }, f() { return this.z; }, g: () => { let x; x = 1 + {}; return x; } };\nconst a2 = { m() { return this.z; }, f() { return this.z; }, g: () => { let x: number | string = 0; x = 2 + {}; return x; } };\nconst a3 = { m() { return this.z; }, f() { return this.z; }, g: () => { let x; [x] = [3 + {}]; return x; } };\nconst a4 = { m() { return this.z; }, f() { return this.z; }, g: () => { let x; x = [4 + {}]; return x; } };\nconst a6 = { m() { return this.z; }, f() { return this.z; }, g: () => { let x; x = { a: 6 + {} }; return x; } };\nconst a7 = { m() { return this.z; }, f() { return this.z; }, g: () => { let x; for (x of [7 + {}]) {} return x; } };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L17": { + "files": { + "a.js": "#!/usr/bin/env -S node --require ./hook\nrequire(\"./B\");\n", + "b.js": "module.exports = 1;\n", + "c.js": "require(\"./b\");\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" }, \"files\": [\"a.js\", \"c.js\"] }\n" + } + }, + "62-L18": { + "files": { + "a.ts": "declare function id(x: T): T;\nconst n1 = { m() { return this.z; }, f() { return this.z; }, g: () => id(2 + {}) };\nconst n5 = { m() { return this.z; }, f() { return this.z; }, g: () => id(id(6 + {})) };\nconst n9 = { m() { return this.z; }, f() { return this.z; }, g: () => [id(7 + {})] };\nconst n11 = { m() { return this.z; }, f() { return this.z; }, g: () => id({ a: 9 + {} }) };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "62-L19": { + "files": { + "a.ts": "const l1 = { m() { return this.z; }, f() { return this.z; }, g: () => ({ a: 1 + {} }) };\nconst l2 = { m() { return this.z; }, f() { return this.z; }, g: () => ({ a: { b: 2 + {} } }) };\nconst l3 = { m() { return this.z; }, f() { return this.z; }, g: () => [{ a: 3 + {} }] };\nconst l4 = { m() { return this.z; }, f() { return this.z; }, g: () => ({ [\"a\"]: 4 + {} }) };\nconst l5 = { m() { return this.z; }, f() { return this.z; }, g: () => ({ a: 5 + {}, ...{} }) };\nconst l8 = { m() { return this.z; }, f() { return this.z; }, g: () => ({ a: [8 + {}] }) };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "63-L03b": { + "files": { + "a.ts": "export class B { set x(this, v: number) {} }\nexport class H { get x(this): number { return 1; } }\nexport class I { get x(this): number { return 1; } set x(this, v: number) {} }\nexport class J { static set x(this, v: number) {} }\nexport class K { private set x(this, v: number) {} }\nexport class M { get x(): number { return 1; } set x(this, v: number) {} }\nexport class N { get x(this) { return 1; } }\nexport abstract class O { abstract set x(this, v: number); }\nexport declare class P { set x(this, v: number); }\nexport interface Q { set x(this, v: number); get y(this): number }\nexport type R = { set x(this, v: number); get y(this): number }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"declaration\": true, \"isolatedDeclarations\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "63-L04": { + "files": { + "a.ts": "const { a, ...rest } = { a: 1, b: 2, c: 3 };\ndeclare function f(x: typeof rest, y: T): T;\ndeclare function f(x: { b: string }, y: number): number;\nclass C {\n b = \"\";\n c = f(this, 1);\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "63-L05b": { + "files": { + "a.tsx": "declare namespace JSX { interface Element { e: 1 } interface IntrinsicElements { } }\ndeclare const cond: boolean;\nconst o1 = { q: 1 }, o2 = { r: 2 };\ndeclare function Gen(props: T & { pick?: keyof T }): JSX.Element;\nconst x1 = ;\ndeclare function Req(props: T & { z: 1 }): JSX.Element;\nconst x2 = ;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "63-L08": { + "files": { + "a.ts": "declare const bad: { [Symbol.iterator](): { next(): { done: boolean; value: number }; return: number } };\ndeclare function f(...a: number[]): void;\nf(...bad);\nconst arr = [...bad];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "63-L09": { + "files": { + "a.js": "class C {\n constructor() {\n /** @type {ReturnType} */\n this.x = 1;\n }\n x = mk();\n}\nfunction mk() { return new C().x; }\nclass D {\n constructor() {\n this.y = mk2();\n }\n /** @type {ReturnType} */\n y;\n}\nfunction mk2() { return new D().y; }\n", + "b.ts": "new C().x();\nnew D().y();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true }, \"files\": [\"a.js\", \"b.ts\"] }\n" + } + }, + "63-L10": { + "files": { + "a.ts": "const v: 1 = null! as [\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\", { get g(): string; set g(v: number) }, { a: 1 }];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "63-L14b": { + "files": { + "a.ts": "let r: 1; let x: any;\nclass P { a = 1; b = 2; }\ndeclare const p: P;\n({ a: x, ...r } = p);\n({ ...r } = p);\nenum E { A, B }\n({ A: x, ...r } = E);\nnamespace NS { export const a = 1, b = 2; }\n({ a: x, ...r } = NS);\nfunction f() {} f.a = 1; f.b = 2;\n({ a: x, ...r } = f);\ninterface I { a: number; b: number }\ndeclare const i: I;\n({ a: x, ...r } = i);\nclass Box { a!: T; b!: T[]; }\ndeclare const bx: Box;\n({ a: x, ...r } = bx);\n({ a: x, ...r } = P);\ndeclare const u: P | I;\n({ a: x, ...r } = u);\nconst ce = class { a = 1; b = 2 };\n({ a: x, ...r } = new ce());\ntype TL = { a: number; b: number };\ndeclare const tl: TL;\n({ a: x, ...r } = tl);\n({ a: x, ...r } = { a: 1, b: 2 });\nlet need: { b: number; c: number };\n({ a: x, ...need } = p);\nfor ({ a: x, ...r } of [p]) {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "63-L16": { + "files": { + "a.ts": "interface Array { length: number } interface Boolean {} interface CallableFunction {} interface Function {} interface IArguments {} interface NewableFunction {} interface Number {} interface Object {} interface RegExp {} interface String {}\nnamespace N { export type NoInfer = intrinsic; }\ndeclare function g(a: T, b: N.NoInfer): { c: N.NoInfer };\nconst n: 1 = g;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"noLib\": true } }\n" + } + }, + "63-L18b": { + "files": { + "a.ts": "import { x } from \"./café\";\nx;\nconst sentinel: number = \"\";\n", + "café.ts": "export const x = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "71-R04a": { + "files": { + "a.ts": "declare function use(...x: any[]): void;\nfunction F(this: any) { if (F) { use(new.target); } }\nfunction G(this: any) { return G && new.target; }\nconst h = function H(this: any) { if (H) { use(new.target); } };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "71-R04b": { + "files": { + "a.tsx": "declare namespace JSX { interface Element {} interface IntrinsicElements { div: {}; a: {} } }\ndeclare function use(...x: any[]): void;\nfunction div() {}\nif (div) { use(
); }\nif (div) { use(
); }\nuse(div &&
);\nasync function t(a: Promise) { if (a) { use(); } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "71-R04c": { + "files": { + "a.tsx": "declare namespace JSX { interface Element {} interface IntrinsicElements { div: {}; call: { (): void; x?: number } } }\ndeclare function use(...x: any[]): void;\ndeclare const ie: JSX.IntrinsicElements;\nuse(ie.call &&
);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "71-R04d": { + "files": { + "a.ts": "function t(p: () => void) { if (p) { const g = (x: any): p is any => true; } }\nfunction u(p: () => void) { if (p) { const g = (x: any): asserts p => {}; } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "71-R04e": { + "files": { + "a.ts": "export {};\ndeclare function use(...x: any[]): void;\nclass G { f() {} g(): void {} h(x: T): T { return x; } }\nclass A { f() {} g(): void {} p = () => {};\n m(other: A) {\n use(this.f && other.f());\n use(this.p && other.p());\n use(other.f && this.f());\n use(this.g && other.g());\n use(this.f && this.f());\n }\n}\ndeclare const g1: G, g2: G, g3: G;\nuse(g1.f && g2.f());\nuse(g1.g && g2.g());\nuse(g1.h && g2.h(\"\"));\nuse(g1.f && g3.f());\nfunction tp(t: T, a: A) { use(t.f && a.f()); use(t.g && a.g()); use(t.f && t.f()); }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "71-R07": { + "files": { + "a.ts": "import d from \"./m\";\nexport const x = d.foo;\nconst sentinel: number = \"\";\n", + "m.ts": "import { x } from \"./a\";\nconst o = { foo: x };\nexport = o;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "71-R07b": { + "files": { + "a.ts": "import d from \"./m\";\nexport const x = d.foo;\nconst sentinel: number = \"\";\n", + "m.js": "const { x } = require(\"./a\");\nconst o = { foo: x };\nmodule.exports = o;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "71-R07c": { + "files": { + "a.ts": "import { a2 } from \"./b\";\nexport const other = 1;\nconst sentinel: number = \"\";\n", + "b.ts": "import { a2 } from \"./a\";\nexport const other = 1;\n", + "c.ts": "import { s2 } from \"./c\";\nexport { s2 as other };\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "71-R09a": { + "files": { + "a.ts": "import { I } from \"./m\";\nimport { T } from \"./m\";\nimport { NT } from \"./m\";\nimport D from \"./m\";\nimport * as ns from \"./m\";\nimport M = ns.NT;\nexport const t1 = I;\nexport const t2 = T;\nexport const t3 = NT;\nexport const t4 = D;\nexport const t5 = M;\nconst sentinel: number = \"\";\n", + "m.ts": "export interface I { i: number }\nexport type T = number;\nexport namespace NT { export type X = 1 }\nexport default interface D {}\nexport class C {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"noUnusedLocals\": true, \"noUnusedParameters\": true } }\n" + } + }, + "71-R12a": { + "files": { + "a.ts": "export {};\ndeclare function dec(...x: any[]): (c: any, ctx: any) => void;\ndeclare const o: any;\nconst e1 = @dec(#i in o) class { #i = 1; };\nconst e2 = @dec(o.#i) class { #i = 1; };\nconst e3 = @dec(() => o.#i) class { #i = 1; };\nconst e4 = @dec((x: E4) => x.#i) class E4 { #i = 1; };\nconst e5 = @dec(() => e5.#s) class { static #s = 1; };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"esnext.decorators\"], \"target\": \"es2022\" } }\n" + } + }, + "71-R12b": { + "files": { + "a.ts": "export {};\ndeclare function dec(...x: any[]): (c: any, ctx: any) => void;\nclass Out { #i = \"outer\"; m(x: Out) { return @dec(x.#i.length, #i in x) class { #i = 1; }; } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"esnext.decorators\"], \"target\": \"es2022\" } }\n" + } + }, + "71-R15a": { + "files": { + "a.ts": "export {};\ntype Ctor = new (...a: any[]) => T;\nfunction h1(B: T & U) { return class extends B { static s = \"ok\"; }; }\nfunction h2(B: T & U) { return class extends B {}; }\nfunction h5(B: T & U) { return class extends B {}; }\nfunction h7(B: T & U) { return class extends B {}; }\nfunction h9(B: U & T) { return class extends B {}; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\" } }\n" + } + }, + "71-R15b": { + "files": { + "a.ts": "export {};\ntype Ctor = new (...a: any[]) => T;\nfunction g4(B: T & U) { return class extends B { static s = 1; }; }\nfunction g5(B: T & { s: string; f(): void }) { return class extends B { static s = 1; static f = 1; }; }\nfunction g7(B: T & { [k: string]: number }) { return class extends B { static s = \"x\"; }; }\nfunction h14(B: T & Record) { return class extends B {}; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\" } }\n" + } + }, + "71-R15c": { + "files": { + "a.ts": "export {};\ntype Ctor = new (...a: any[]) => T;\ndeclare const key: string;\nfunction i1(B: T) { return class extends B { static s = \"x\"; }; }\nfunction i2(B: T) { return class extends B { static [k: string]: number; static s = \"x\"; }; }\nfunction i3(B: T) { return class extends B { static [k: string]: number; static [key] = \"x\"; }; }\nfunction i4(B: T) { return class extends B { static [k: string]: number; static [k: number]: string; }; }\nfunction i7(B: T) { return class extends B { static s = 1; static m() {} }; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\" } }\n" + } + }, + "72-R01": { + "files": { + "a.ts": "const c0 = 1;\nconst c1 = c0 + 1;\nconst c2 = c1 + 1;\nconst c3 = c2 + 1;\nconst c4 = c3 + 1;\nconst c5 = c4 + 1;\nconst c6 = c5 + 1;\nconst c7 = c6 + 1;\nconst c8 = c7 + 1;\nconst c9 = c8 + 1;\nconst c10 = c9 + 1;\nconst c11 = c10 + 1;\nconst c12 = c11 + 1;\nconst c13 = c12 + 1;\nconst c14 = c13 + 1;\nconst c15 = c14 + 1;\nconst c16 = c15 + 1;\nconst c17 = c16 + 1;\nconst c18 = c17 + 1;\nconst c19 = c18 + 1;\nconst c20 = c19 + 1;\nconst c21 = c20 + 1;\nconst c22 = c21 + 1;\nconst c23 = c22 + 1;\nconst c24 = c23 + 1;\nconst c25 = c24 + 1;\nconst c26 = c25 + 1;\nconst c27 = c26 + 1;\nconst c28 = c27 + 1;\nconst c29 = c28 + 1;\nconst c30 = c29 + 1;\nconst c31 = c30 + 1;\nconst c32 = c31 + 1;\nconst c33 = c32 + 1;\nconst c34 = c33 + 1;\nconst c35 = c34 + 1;\nconst c36 = c35 + 1;\nconst c37 = c36 + 1;\nconst c38 = c37 + 1;\nconst c39 = c38 + 1;\nconst c40 = c39 + 1;\nconst c41 = c40 + 1;\nconst c42 = c41 + 1;\nconst c43 = c42 + 1;\nconst c44 = c43 + 1;\nconst c45 = c44 + 1;\nconst c46 = c45 + 1;\nconst c47 = c46 + 1;\nconst c48 = c47 + 1;\nconst c49 = c48 + 1;\nconst c50 = c49 + 1;\nconst c51 = c50 + 1;\nconst c52 = c51 + 1;\nconst c53 = c52 + 1;\nconst c54 = c53 + 1;\nconst c55 = c54 + 1;\nconst c56 = c55 + 1;\nconst c57 = c56 + 1;\nconst c58 = c57 + 1;\nconst c59 = c58 + 1;\nconst c60 = c59 + 1;\nconst c61 = c60 + 1;\nconst c62 = c61 + 1;\nconst c63 = c62 + 1;\nconst c64 = c63 + 1;\nconst c65 = c64 + 1;\nconst c66 = c65 + 1;\nconst c67 = c66 + 1;\nconst c68 = c67 + 1;\nconst c69 = c68 + 1;\nconst c70 = c69 + 1;\nconst c71 = c70 + 1;\nconst c72 = c71 + 1;\nconst c73 = c72 + 1;\nconst c74 = c73 + 1;\nconst c75 = c74 + 1;\nconst c76 = c75 + 1;\nconst c77 = c76 + 1;\nconst c78 = c77 + 1;\nconst c79 = c78 + 1;\nconst c80 = c79 + 1;\nconst c81 = c80 + 1;\nconst c82 = c81 + 1;\nconst c83 = c82 + 1;\nconst c84 = c83 + 1;\nconst c85 = c84 + 1;\nconst c86 = c85 + 1;\nconst c87 = c86 + 1;\nconst c88 = c87 + 1;\nconst c89 = c88 + 1;\nconst c90 = c89 + 1;\nconst c91 = c90 + 1;\nconst c92 = c91 + 1;\nconst c93 = c92 + 1;\nconst c94 = c93 + 1;\nconst c95 = c94 + 1;\nconst c96 = c95 + 1;\nconst c97 = c96 + 1;\nconst c98 = c97 + 1;\nconst c99 = c98 + 1;\nconst c100 = c99 + 1;\nconst c101 = c100 + 1;\nconst c102 = c101 + 1;\nconst c103 = c102 + 1;\nconst c104 = c103 + 1;\nconst c105 = c104 + 1;\nconst c106 = c105 + 1;\nconst c107 = c106 + 1;\nconst c108 = c107 + 1;\nconst c109 = c108 + 1;\nconst c110 = c109 + 1;\nconst c111 = c110 + 1;\nconst c112 = c111 + 1;\nconst c113 = c112 + 1;\nconst c114 = c113 + 1;\nconst c115 = c114 + 1;\nconst c116 = c115 + 1;\nconst c117 = c116 + 1;\nconst c118 = c117 + 1;\nconst c119 = c118 + 1;\nconst c120 = c119 + 1;\nconst c121 = c120 + 1;\nconst c122 = c121 + 1;\nconst c123 = c122 + 1;\nconst c124 = c123 + 1;\nconst c125 = c124 + 1;\nconst c126 = c125 + 1;\nconst c127 = c126 + 1;\nconst c128 = c127 + 1;\nconst c129 = c128 + 1;\nconst c130 = c129 + 1;\nconst c131 = c130 + 1;\nconst c132 = c131 + 1;\nconst c133 = c132 + 1;\nconst c134 = c133 + 1;\nconst c135 = c134 + 1;\nconst c136 = c135 + 1;\nconst c137 = c136 + 1;\nconst c138 = c137 + 1;\nconst c139 = c138 + 1;\nconst c140 = c139 + 1;\nconst c141 = c140 + 1;\nconst c142 = c141 + 1;\nconst c143 = c142 + 1;\nconst c144 = c143 + 1;\nconst c145 = c144 + 1;\nconst c146 = c145 + 1;\nconst c147 = c146 + 1;\nconst c148 = c147 + 1;\nconst c149 = c148 + 1;\nconst c150 = c149 + 1;\nconst c151 = c150 + 1;\nconst c152 = c151 + 1;\nconst c153 = c152 + 1;\nconst c154 = c153 + 1;\nconst c155 = c154 + 1;\nconst c156 = c155 + 1;\nconst c157 = c156 + 1;\nconst c158 = c157 + 1;\nconst c159 = c158 + 1;\nconst c160 = c159 + 1;\nconst c161 = c160 + 1;\nconst c162 = c161 + 1;\nconst c163 = c162 + 1;\nconst c164 = c163 + 1;\nconst c165 = c164 + 1;\nconst c166 = c165 + 1;\nconst c167 = c166 + 1;\nconst c168 = c167 + 1;\nconst c169 = c168 + 1;\nconst c170 = c169 + 1;\nconst c171 = c170 + 1;\nconst c172 = c171 + 1;\nconst c173 = c172 + 1;\nconst c174 = c173 + 1;\nconst c175 = c174 + 1;\nconst c176 = c175 + 1;\nconst c177 = c176 + 1;\nconst c178 = c177 + 1;\nconst c179 = c178 + 1;\nconst c180 = c179 + 1;\nconst c181 = c180 + 1;\nconst c182 = c181 + 1;\nconst c183 = c182 + 1;\nconst c184 = c183 + 1;\nconst c185 = c184 + 1;\nconst c186 = c185 + 1;\nconst c187 = c186 + 1;\nconst c188 = c187 + 1;\nconst c189 = c188 + 1;\nconst c190 = c189 + 1;\nconst c191 = c190 + 1;\nconst c192 = c191 + 1;\nconst c193 = c192 + 1;\nconst c194 = c193 + 1;\nconst c195 = c194 + 1;\nconst c196 = c195 + 1;\nconst c197 = c196 + 1;\nconst c198 = c197 + 1;\nconst c199 = c198 + 1;\nconst c200 = c199 + 1;\nconst c201 = c200 + 1;\nconst c202 = c201 + 1;\nconst c203 = c202 + 1;\nconst c204 = c203 + 1;\nconst c205 = c204 + 1;\nconst c206 = c205 + 1;\nconst c207 = c206 + 1;\nconst c208 = c207 + 1;\nconst c209 = c208 + 1;\nconst c210 = c209 + 1;\nconst c211 = c210 + 1;\nconst c212 = c211 + 1;\nconst c213 = c212 + 1;\nconst c214 = c213 + 1;\nconst c215 = c214 + 1;\nconst c216 = c215 + 1;\nconst c217 = c216 + 1;\nconst c218 = c217 + 1;\nconst c219 = c218 + 1;\nconst c220 = c219 + 1;\nconst c221 = c220 + 1;\nconst c222 = c221 + 1;\nconst c223 = c222 + 1;\nconst c224 = c223 + 1;\nconst c225 = c224 + 1;\nconst c226 = c225 + 1;\nconst c227 = c226 + 1;\nconst c228 = c227 + 1;\nconst c229 = c228 + 1;\nconst c230 = c229 + 1;\nconst c231 = c230 + 1;\nconst c232 = c231 + 1;\nconst c233 = c232 + 1;\nconst c234 = c233 + 1;\nconst c235 = c234 + 1;\nconst c236 = c235 + 1;\nconst c237 = c236 + 1;\nconst c238 = c237 + 1;\nconst c239 = c238 + 1;\nconst c240 = c239 + 1;\nconst c241 = c240 + 1;\nconst c242 = c241 + 1;\nconst c243 = c242 + 1;\nconst c244 = c243 + 1;\nconst c245 = c244 + 1;\nconst c246 = c245 + 1;\nconst c247 = c246 + 1;\nconst c248 = c247 + 1;\nconst c249 = c248 + 1;\nconst c250 = c249 + 1;\nconst c251 = c250 + 1;\nconst c252 = c251 + 1;\nconst c253 = c252 + 1;\nconst c254 = c253 + 1;\nconst c255 = c254 + 1;\nconst c256 = c255 + 1;\nconst c257 = c256 + 1;\nconst c258 = c257 + 1;\nconst c259 = c258 + 1;\nconst c260 = c259 + 1;\nconst c261 = c260 + 1;\nconst c262 = c261 + 1;\nconst c263 = c262 + 1;\nconst c264 = c263 + 1;\nconst c265 = c264 + 1;\nconst c266 = c265 + 1;\nconst c267 = c266 + 1;\nconst c268 = c267 + 1;\nconst c269 = c268 + 1;\nconst c270 = c269 + 1;\nconst c271 = c270 + 1;\nconst c272 = c271 + 1;\nconst c273 = c272 + 1;\nconst c274 = c273 + 1;\nconst c275 = c274 + 1;\nconst c276 = c275 + 1;\nconst c277 = c276 + 1;\nconst c278 = c277 + 1;\nconst c279 = c278 + 1;\nconst c280 = c279 + 1;\nconst c281 = c280 + 1;\nconst c282 = c281 + 1;\nconst c283 = c282 + 1;\nconst c284 = c283 + 1;\nconst c285 = c284 + 1;\nconst c286 = c285 + 1;\nconst c287 = c286 + 1;\nconst c288 = c287 + 1;\nconst c289 = c288 + 1;\nconst c290 = c289 + 1;\nconst c291 = c290 + 1;\nconst c292 = c291 + 1;\nconst c293 = c292 + 1;\nconst c294 = c293 + 1;\nconst c295 = c294 + 1;\nconst c296 = c295 + 1;\nconst c297 = c296 + 1;\nconst c298 = c297 + 1;\nconst c299 = c298 + 1;\nconst c300 = c299 + 1;\nconst c301 = c300 + 1;\nconst c302 = c301 + 1;\nconst c303 = c302 + 1;\nconst c304 = c303 + 1;\nconst c305 = c304 + 1;\nconst c306 = c305 + 1;\nconst c307 = c306 + 1;\nconst c308 = c307 + 1;\nconst c309 = c308 + 1;\nconst c310 = c309 + 1;\nconst c311 = c310 + 1;\nconst c312 = c311 + 1;\nconst c313 = c312 + 1;\nconst c314 = c313 + 1;\nconst c315 = c314 + 1;\nconst c316 = c315 + 1;\nconst c317 = c316 + 1;\nconst c318 = c317 + 1;\nconst c319 = c318 + 1;\nconst c320 = c319 + 1;\nconst c321 = c320 + 1;\nconst c322 = c321 + 1;\nconst c323 = c322 + 1;\nconst c324 = c323 + 1;\nconst c325 = c324 + 1;\nconst c326 = c325 + 1;\nconst c327 = c326 + 1;\nconst c328 = c327 + 1;\nconst c329 = c328 + 1;\nconst c330 = c329 + 1;\nconst c331 = c330 + 1;\nconst c332 = c331 + 1;\nconst c333 = c332 + 1;\nconst c334 = c333 + 1;\nconst c335 = c334 + 1;\nconst c336 = c335 + 1;\nconst c337 = c336 + 1;\nconst c338 = c337 + 1;\nconst c339 = c338 + 1;\nconst c340 = c339 + 1;\nconst c341 = c340 + 1;\nconst c342 = c341 + 1;\nconst c343 = c342 + 1;\nconst c344 = c343 + 1;\nconst c345 = c344 + 1;\nconst c346 = c345 + 1;\nconst c347 = c346 + 1;\nconst c348 = c347 + 1;\nconst c349 = c348 + 1;\nconst c350 = c349 + 1;\nconst c351 = c350 + 1;\nconst c352 = c351 + 1;\nconst c353 = c352 + 1;\nconst c354 = c353 + 1;\nconst c355 = c354 + 1;\nconst c356 = c355 + 1;\nconst c357 = c356 + 1;\nconst c358 = c357 + 1;\nconst c359 = c358 + 1;\nconst c360 = c359 + 1;\nconst c361 = c360 + 1;\nconst c362 = c361 + 1;\nconst c363 = c362 + 1;\nconst c364 = c363 + 1;\nconst c365 = c364 + 1;\nconst c366 = c365 + 1;\nconst c367 = c366 + 1;\nconst c368 = c367 + 1;\nconst c369 = c368 + 1;\nconst c370 = c369 + 1;\nconst c371 = c370 + 1;\nconst c372 = c371 + 1;\nconst c373 = c372 + 1;\nconst c374 = c373 + 1;\nconst c375 = c374 + 1;\nconst c376 = c375 + 1;\nconst c377 = c376 + 1;\nconst c378 = c377 + 1;\nconst c379 = c378 + 1;\nconst c380 = c379 + 1;\nconst c381 = c380 + 1;\nconst c382 = c381 + 1;\nconst c383 = c382 + 1;\nconst c384 = c383 + 1;\nconst c385 = c384 + 1;\nconst c386 = c385 + 1;\nconst c387 = c386 + 1;\nconst c388 = c387 + 1;\nconst c389 = c388 + 1;\nconst c390 = c389 + 1;\nconst c391 = c390 + 1;\nconst c392 = c391 + 1;\nconst c393 = c392 + 1;\nconst c394 = c393 + 1;\nconst c395 = c394 + 1;\nconst c396 = c395 + 1;\nconst c397 = c396 + 1;\nconst c398 = c397 + 1;\nconst c399 = c398 + 1;\nconst c400 = c399 + 1;\nconst c401 = c400 + 1;\nconst c402 = c401 + 1;\nconst c403 = c402 + 1;\nconst c404 = c403 + 1;\nconst c405 = c404 + 1;\nconst c406 = c405 + 1;\nconst c407 = c406 + 1;\nconst c408 = c407 + 1;\nconst c409 = c408 + 1;\nconst c410 = c409 + 1;\nconst c411 = c410 + 1;\nconst c412 = c411 + 1;\nconst c413 = c412 + 1;\nconst c414 = c413 + 1;\nconst c415 = c414 + 1;\nconst c416 = c415 + 1;\nconst c417 = c416 + 1;\nconst c418 = c417 + 1;\nconst c419 = c418 + 1;\nconst c420 = c419 + 1;\nconst c421 = c420 + 1;\nconst c422 = c421 + 1;\nconst c423 = c422 + 1;\nconst c424 = c423 + 1;\nconst c425 = c424 + 1;\nconst c426 = c425 + 1;\nconst c427 = c426 + 1;\nconst c428 = c427 + 1;\nconst c429 = c428 + 1;\nconst c430 = c429 + 1;\nconst c431 = c430 + 1;\nconst c432 = c431 + 1;\nconst c433 = c432 + 1;\nconst c434 = c433 + 1;\nconst c435 = c434 + 1;\nconst c436 = c435 + 1;\nconst c437 = c436 + 1;\nconst c438 = c437 + 1;\nconst c439 = c438 + 1;\nconst c440 = c439 + 1;\nconst c441 = c440 + 1;\nconst c442 = c441 + 1;\nconst c443 = c442 + 1;\nconst c444 = c443 + 1;\nconst c445 = c444 + 1;\nconst c446 = c445 + 1;\nconst c447 = c446 + 1;\nconst c448 = c447 + 1;\nconst c449 = c448 + 1;\nconst c450 = c449 + 1;\nconst c451 = c450 + 1;\nconst c452 = c451 + 1;\nconst c453 = c452 + 1;\nconst c454 = c453 + 1;\nconst c455 = c454 + 1;\nconst c456 = c455 + 1;\nconst c457 = c456 + 1;\nconst c458 = c457 + 1;\nconst c459 = c458 + 1;\nconst c460 = c459 + 1;\nconst c461 = c460 + 1;\nconst c462 = c461 + 1;\nconst c463 = c462 + 1;\nconst c464 = c463 + 1;\nconst c465 = c464 + 1;\nconst c466 = c465 + 1;\nconst c467 = c466 + 1;\nconst c468 = c467 + 1;\nconst c469 = c468 + 1;\nconst c470 = c469 + 1;\nconst c471 = c470 + 1;\nconst c472 = c471 + 1;\nconst c473 = c472 + 1;\nconst c474 = c473 + 1;\nconst c475 = c474 + 1;\nconst c476 = c475 + 1;\nconst c477 = c476 + 1;\nconst c478 = c477 + 1;\nconst c479 = c478 + 1;\nconst c480 = c479 + 1;\nconst c481 = c480 + 1;\nconst c482 = c481 + 1;\nconst c483 = c482 + 1;\nconst c484 = c483 + 1;\nconst c485 = c484 + 1;\nconst c486 = c485 + 1;\nconst c487 = c486 + 1;\nconst c488 = c487 + 1;\nconst c489 = c488 + 1;\nconst c490 = c489 + 1;\nconst c491 = c490 + 1;\nconst c492 = c491 + 1;\nconst c493 = c492 + 1;\nconst c494 = c493 + 1;\nconst c495 = c494 + 1;\nconst c496 = c495 + 1;\nconst c497 = c496 + 1;\nconst c498 = c497 + 1;\nconst c499 = c498 + 1;\nconst c500 = c499 + 1;\nconst c501 = c500 + 1;\nconst c502 = c501 + 1;\nconst c503 = c502 + 1;\nconst c504 = c503 + 1;\nconst c505 = c504 + 1;\nconst c506 = c505 + 1;\nconst c507 = c506 + 1;\nconst c508 = c507 + 1;\nconst c509 = c508 + 1;\nconst c510 = c509 + 1;\nconst c511 = c510 + 1;\nconst c512 = c511 + 1;\nconst c513 = c512 + 1;\nconst c514 = c513 + 1;\nconst c515 = c514 + 1;\nconst c516 = c515 + 1;\nconst c517 = c516 + 1;\nconst c518 = c517 + 1;\nconst c519 = c518 + 1;\nconst c520 = c519 + 1;\nconst c521 = c520 + 1;\nconst c522 = c521 + 1;\nconst c523 = c522 + 1;\nconst c524 = c523 + 1;\nconst c525 = c524 + 1;\nconst c526 = c525 + 1;\nconst c527 = c526 + 1;\nconst c528 = c527 + 1;\nconst c529 = c528 + 1;\nconst c530 = c529 + 1;\nconst c531 = c530 + 1;\nconst c532 = c531 + 1;\nconst c533 = c532 + 1;\nconst c534 = c533 + 1;\nconst c535 = c534 + 1;\nconst c536 = c535 + 1;\nconst c537 = c536 + 1;\nconst c538 = c537 + 1;\nconst c539 = c538 + 1;\nconst c540 = c539 + 1;\nconst c541 = c540 + 1;\nconst c542 = c541 + 1;\nconst c543 = c542 + 1;\nconst c544 = c543 + 1;\nconst c545 = c544 + 1;\nconst c546 = c545 + 1;\nconst c547 = c546 + 1;\nconst c548 = c547 + 1;\nconst c549 = c548 + 1;\nconst c550 = c549 + 1;\nconst c551 = c550 + 1;\nconst c552 = c551 + 1;\nconst c553 = c552 + 1;\nconst c554 = c553 + 1;\nconst c555 = c554 + 1;\nconst c556 = c555 + 1;\nconst c557 = c556 + 1;\nconst c558 = c557 + 1;\nconst c559 = c558 + 1;\nconst c560 = c559 + 1;\nconst c561 = c560 + 1;\nconst c562 = c561 + 1;\nconst c563 = c562 + 1;\nconst c564 = c563 + 1;\nconst c565 = c564 + 1;\nconst c566 = c565 + 1;\nconst c567 = c566 + 1;\nconst c568 = c567 + 1;\nconst c569 = c568 + 1;\nconst c570 = c569 + 1;\nconst c571 = c570 + 1;\nconst c572 = c571 + 1;\nconst c573 = c572 + 1;\nconst c574 = c573 + 1;\nconst c575 = c574 + 1;\nconst c576 = c575 + 1;\nconst c577 = c576 + 1;\nconst c578 = c577 + 1;\nconst c579 = c578 + 1;\nconst c580 = c579 + 1;\nconst c581 = c580 + 1;\nconst c582 = c581 + 1;\nconst c583 = c582 + 1;\nconst c584 = c583 + 1;\nconst c585 = c584 + 1;\nconst c586 = c585 + 1;\nconst c587 = c586 + 1;\nconst c588 = c587 + 1;\nconst c589 = c588 + 1;\nconst c590 = c589 + 1;\nconst c591 = c590 + 1;\nconst c592 = c591 + 1;\nconst c593 = c592 + 1;\nconst c594 = c593 + 1;\nconst c595 = c594 + 1;\nconst c596 = c595 + 1;\nconst c597 = c596 + 1;\nconst c598 = c597 + 1;\nconst c599 = c598 + 1;\nconst c600 = c599 + 1;\nconst c601 = c600 + 1;\nconst c602 = c601 + 1;\nconst c603 = c602 + 1;\nconst c604 = c603 + 1;\nconst c605 = c604 + 1;\nconst c606 = c605 + 1;\nconst c607 = c606 + 1;\nconst c608 = c607 + 1;\nconst c609 = c608 + 1;\nconst c610 = c609 + 1;\nconst c611 = c610 + 1;\nconst c612 = c611 + 1;\nconst c613 = c612 + 1;\nconst c614 = c613 + 1;\nconst c615 = c614 + 1;\nconst c616 = c615 + 1;\nconst c617 = c616 + 1;\nconst c618 = c617 + 1;\nconst c619 = c618 + 1;\nconst c620 = c619 + 1;\nconst c621 = c620 + 1;\nconst c622 = c621 + 1;\nconst c623 = c622 + 1;\nconst c624 = c623 + 1;\nconst c625 = c624 + 1;\nconst c626 = c625 + 1;\nconst c627 = c626 + 1;\nconst c628 = c627 + 1;\nconst c629 = c628 + 1;\nconst c630 = c629 + 1;\nconst c631 = c630 + 1;\nconst c632 = c631 + 1;\nconst c633 = c632 + 1;\nconst c634 = c633 + 1;\nconst c635 = c634 + 1;\nconst c636 = c635 + 1;\nconst c637 = c636 + 1;\nconst c638 = c637 + 1;\nconst c639 = c638 + 1;\nconst c640 = c639 + 1;\nconst c641 = c640 + 1;\nconst c642 = c641 + 1;\nconst c643 = c642 + 1;\nconst c644 = c643 + 1;\nconst c645 = c644 + 1;\nconst c646 = c645 + 1;\nconst c647 = c646 + 1;\nconst c648 = c647 + 1;\nconst c649 = c648 + 1;\nconst c650 = c649 + 1;\nconst c651 = c650 + 1;\nconst c652 = c651 + 1;\nconst c653 = c652 + 1;\nconst c654 = c653 + 1;\nconst c655 = c654 + 1;\nconst c656 = c655 + 1;\nconst c657 = c656 + 1;\nconst c658 = c657 + 1;\nconst c659 = c658 + 1;\nconst c660 = c659 + 1;\nconst c661 = c660 + 1;\nconst c662 = c661 + 1;\nconst c663 = c662 + 1;\nconst c664 = c663 + 1;\nconst c665 = c664 + 1;\nconst c666 = c665 + 1;\nconst c667 = c666 + 1;\nconst c668 = c667 + 1;\nconst c669 = c668 + 1;\nconst c670 = c669 + 1;\nconst c671 = c670 + 1;\nconst c672 = c671 + 1;\nconst c673 = c672 + 1;\nconst c674 = c673 + 1;\nconst c675 = c674 + 1;\nconst c676 = c675 + 1;\nconst c677 = c676 + 1;\nconst c678 = c677 + 1;\nconst c679 = c678 + 1;\nconst c680 = c679 + 1;\nconst c681 = c680 + 1;\nconst c682 = c681 + 1;\nconst c683 = c682 + 1;\nconst c684 = c683 + 1;\nconst c685 = c684 + 1;\nconst c686 = c685 + 1;\nconst c687 = c686 + 1;\nconst c688 = c687 + 1;\nconst c689 = c688 + 1;\nconst c690 = c689 + 1;\nconst c691 = c690 + 1;\nconst c692 = c691 + 1;\nconst c693 = c692 + 1;\nconst c694 = c693 + 1;\nconst c695 = c694 + 1;\nconst c696 = c695 + 1;\nconst c697 = c696 + 1;\nconst c698 = c697 + 1;\nconst c699 = c698 + 1;\nconst c700 = c699 + 1;\nconst c701 = c700 + 1;\nconst c702 = c701 + 1;\nconst c703 = c702 + 1;\nconst c704 = c703 + 1;\nconst c705 = c704 + 1;\nconst c706 = c705 + 1;\nconst c707 = c706 + 1;\nconst c708 = c707 + 1;\nconst c709 = c708 + 1;\nconst c710 = c709 + 1;\nconst c711 = c710 + 1;\nconst c712 = c711 + 1;\nconst c713 = c712 + 1;\nconst c714 = c713 + 1;\nconst c715 = c714 + 1;\nconst c716 = c715 + 1;\nconst c717 = c716 + 1;\nconst c718 = c717 + 1;\nconst c719 = c718 + 1;\nconst c720 = c719 + 1;\nconst c721 = c720 + 1;\nconst c722 = c721 + 1;\nconst c723 = c722 + 1;\nconst c724 = c723 + 1;\nconst c725 = c724 + 1;\nconst c726 = c725 + 1;\nconst c727 = c726 + 1;\nconst c728 = c727 + 1;\nconst c729 = c728 + 1;\nconst c730 = c729 + 1;\nconst c731 = c730 + 1;\nconst c732 = c731 + 1;\nconst c733 = c732 + 1;\nconst c734 = c733 + 1;\nconst c735 = c734 + 1;\nconst c736 = c735 + 1;\nconst c737 = c736 + 1;\nconst c738 = c737 + 1;\nconst c739 = c738 + 1;\nconst c740 = c739 + 1;\nconst c741 = c740 + 1;\nconst c742 = c741 + 1;\nconst c743 = c742 + 1;\nconst c744 = c743 + 1;\nconst c745 = c744 + 1;\nconst c746 = c745 + 1;\nconst c747 = c746 + 1;\nconst c748 = c747 + 1;\nconst c749 = c748 + 1;\nconst c750 = c749 + 1;\nconst c751 = c750 + 1;\nconst c752 = c751 + 1;\nconst c753 = c752 + 1;\nconst c754 = c753 + 1;\nconst c755 = c754 + 1;\nconst c756 = c755 + 1;\nconst c757 = c756 + 1;\nconst c758 = c757 + 1;\nconst c759 = c758 + 1;\nconst c760 = c759 + 1;\nconst c761 = c760 + 1;\nconst c762 = c761 + 1;\nconst c763 = c762 + 1;\nconst c764 = c763 + 1;\nconst c765 = c764 + 1;\nconst c766 = c765 + 1;\nconst c767 = c766 + 1;\nconst c768 = c767 + 1;\nconst c769 = c768 + 1;\nconst c770 = c769 + 1;\nconst c771 = c770 + 1;\nconst c772 = c771 + 1;\nconst c773 = c772 + 1;\nconst c774 = c773 + 1;\nconst c775 = c774 + 1;\nconst c776 = c775 + 1;\nconst c777 = c776 + 1;\nconst c778 = c777 + 1;\nconst c779 = c778 + 1;\nconst c780 = c779 + 1;\nconst c781 = c780 + 1;\nconst c782 = c781 + 1;\nconst c783 = c782 + 1;\nconst c784 = c783 + 1;\nconst c785 = c784 + 1;\nconst c786 = c785 + 1;\nconst c787 = c786 + 1;\nconst c788 = c787 + 1;\nconst c789 = c788 + 1;\nconst c790 = c789 + 1;\nconst c791 = c790 + 1;\nconst c792 = c791 + 1;\nconst c793 = c792 + 1;\nconst c794 = c793 + 1;\nconst c795 = c794 + 1;\nconst c796 = c795 + 1;\nconst c797 = c796 + 1;\nconst c798 = c797 + 1;\nconst c799 = c798 + 1;\nconst c800 = c799 + 1;\nconst c801 = c800 + 1;\nconst c802 = c801 + 1;\nconst c803 = c802 + 1;\nconst c804 = c803 + 1;\nconst c805 = c804 + 1;\nconst c806 = c805 + 1;\nconst c807 = c806 + 1;\nconst c808 = c807 + 1;\nconst c809 = c808 + 1;\nconst c810 = c809 + 1;\nconst c811 = c810 + 1;\nconst c812 = c811 + 1;\nconst c813 = c812 + 1;\nconst c814 = c813 + 1;\nconst c815 = c814 + 1;\nconst c816 = c815 + 1;\nconst c817 = c816 + 1;\nconst c818 = c817 + 1;\nconst c819 = c818 + 1;\nconst c820 = c819 + 1;\nconst c821 = c820 + 1;\nconst c822 = c821 + 1;\nconst c823 = c822 + 1;\nconst c824 = c823 + 1;\nconst c825 = c824 + 1;\nconst c826 = c825 + 1;\nconst c827 = c826 + 1;\nconst c828 = c827 + 1;\nconst c829 = c828 + 1;\nconst c830 = c829 + 1;\nconst c831 = c830 + 1;\nconst c832 = c831 + 1;\nconst c833 = c832 + 1;\nconst c834 = c833 + 1;\nconst c835 = c834 + 1;\nconst c836 = c835 + 1;\nconst c837 = c836 + 1;\nconst c838 = c837 + 1;\nconst c839 = c838 + 1;\nconst c840 = c839 + 1;\nconst c841 = c840 + 1;\nconst c842 = c841 + 1;\nconst c843 = c842 + 1;\nconst c844 = c843 + 1;\nconst c845 = c844 + 1;\nconst c846 = c845 + 1;\nconst c847 = c846 + 1;\nconst c848 = c847 + 1;\nconst c849 = c848 + 1;\nconst c850 = c849 + 1;\nconst c851 = c850 + 1;\nconst c852 = c851 + 1;\nconst c853 = c852 + 1;\nconst c854 = c853 + 1;\nconst c855 = c854 + 1;\nconst c856 = c855 + 1;\nconst c857 = c856 + 1;\nconst c858 = c857 + 1;\nconst c859 = c858 + 1;\nconst c860 = c859 + 1;\nconst c861 = c860 + 1;\nconst c862 = c861 + 1;\nconst c863 = c862 + 1;\nconst c864 = c863 + 1;\nconst c865 = c864 + 1;\nconst c866 = c865 + 1;\nconst c867 = c866 + 1;\nconst c868 = c867 + 1;\nconst c869 = c868 + 1;\nconst c870 = c869 + 1;\nconst c871 = c870 + 1;\nconst c872 = c871 + 1;\nconst c873 = c872 + 1;\nconst c874 = c873 + 1;\nconst c875 = c874 + 1;\nconst c876 = c875 + 1;\nconst c877 = c876 + 1;\nconst c878 = c877 + 1;\nconst c879 = c878 + 1;\nconst c880 = c879 + 1;\nconst c881 = c880 + 1;\nconst c882 = c881 + 1;\nconst c883 = c882 + 1;\nconst c884 = c883 + 1;\nconst c885 = c884 + 1;\nconst c886 = c885 + 1;\nconst c887 = c886 + 1;\nconst c888 = c887 + 1;\nconst c889 = c888 + 1;\nconst c890 = c889 + 1;\nconst c891 = c890 + 1;\nconst c892 = c891 + 1;\nconst c893 = c892 + 1;\nconst c894 = c893 + 1;\nconst c895 = c894 + 1;\nconst c896 = c895 + 1;\nconst c897 = c896 + 1;\nconst c898 = c897 + 1;\nconst c899 = c898 + 1;\nconst c900 = c899 + 1;\nconst c901 = c900 + 1;\nconst c902 = c901 + 1;\nconst c903 = c902 + 1;\nconst c904 = c903 + 1;\nconst c905 = c904 + 1;\nconst c906 = c905 + 1;\nconst c907 = c906 + 1;\nconst c908 = c907 + 1;\nconst c909 = c908 + 1;\nconst c910 = c909 + 1;\nconst c911 = c910 + 1;\nconst c912 = c911 + 1;\nconst c913 = c912 + 1;\nconst c914 = c913 + 1;\nconst c915 = c914 + 1;\nconst c916 = c915 + 1;\nconst c917 = c916 + 1;\nconst c918 = c917 + 1;\nconst c919 = c918 + 1;\nconst c920 = c919 + 1;\nconst c921 = c920 + 1;\nconst c922 = c921 + 1;\nconst c923 = c922 + 1;\nconst c924 = c923 + 1;\nconst c925 = c924 + 1;\nconst c926 = c925 + 1;\nconst c927 = c926 + 1;\nconst c928 = c927 + 1;\nconst c929 = c928 + 1;\nconst c930 = c929 + 1;\nconst c931 = c930 + 1;\nconst c932 = c931 + 1;\nconst c933 = c932 + 1;\nconst c934 = c933 + 1;\nconst c935 = c934 + 1;\nconst c936 = c935 + 1;\nconst c937 = c936 + 1;\nconst c938 = c937 + 1;\nconst c939 = c938 + 1;\nconst c940 = c939 + 1;\nconst c941 = c940 + 1;\nconst c942 = c941 + 1;\nconst c943 = c942 + 1;\nconst c944 = c943 + 1;\nconst c945 = c944 + 1;\nconst c946 = c945 + 1;\nconst c947 = c946 + 1;\nconst c948 = c947 + 1;\nconst c949 = c948 + 1;\nconst c950 = c949 + 1;\nconst c951 = c950 + 1;\nconst c952 = c951 + 1;\nconst c953 = c952 + 1;\nconst c954 = c953 + 1;\nconst c955 = c954 + 1;\nconst c956 = c955 + 1;\nconst c957 = c956 + 1;\nconst c958 = c957 + 1;\nconst c959 = c958 + 1;\nconst c960 = c959 + 1;\nconst c961 = c960 + 1;\nconst c962 = c961 + 1;\nconst c963 = c962 + 1;\nconst c964 = c963 + 1;\nconst c965 = c964 + 1;\nconst c966 = c965 + 1;\nconst c967 = c966 + 1;\nconst c968 = c967 + 1;\nconst c969 = c968 + 1;\nconst c970 = c969 + 1;\nconst c971 = c970 + 1;\nconst c972 = c971 + 1;\nconst c973 = c972 + 1;\nconst c974 = c973 + 1;\nconst c975 = c974 + 1;\nconst c976 = c975 + 1;\nconst c977 = c976 + 1;\nconst c978 = c977 + 1;\nconst c979 = c978 + 1;\nconst c980 = c979 + 1;\nconst c981 = c980 + 1;\nconst c982 = c981 + 1;\nconst c983 = c982 + 1;\nconst c984 = c983 + 1;\nconst c985 = c984 + 1;\nconst c986 = c985 + 1;\nconst c987 = c986 + 1;\nconst c988 = c987 + 1;\nconst c989 = c988 + 1;\nconst c990 = c989 + 1;\nconst c991 = c990 + 1;\nconst c992 = c991 + 1;\nconst c993 = c992 + 1;\nconst c994 = c993 + 1;\nconst c995 = c994 + 1;\nconst c996 = c995 + 1;\nconst c997 = c996 + 1;\nconst c998 = c997 + 1;\nconst c999 = c998 + 1;\nconst c1000 = c999 + 1;\nconst c1001 = c1000 + 1;\nconst c1002 = c1001 + 1;\nconst c1003 = c1002 + 1;\nconst c1004 = c1003 + 1;\nconst c1005 = c1004 + 1;\nconst c1006 = c1005 + 1;\nconst c1007 = c1006 + 1;\nconst c1008 = c1007 + 1;\nconst c1009 = c1008 + 1;\nconst c1010 = c1009 + 1;\nconst c1011 = c1010 + 1;\nconst c1012 = c1011 + 1;\nconst c1013 = c1012 + 1;\nconst c1014 = c1013 + 1;\nconst c1015 = c1014 + 1;\nconst c1016 = c1015 + 1;\nconst c1017 = c1016 + 1;\nconst c1018 = c1017 + 1;\nconst c1019 = c1018 + 1;\nconst c1020 = c1019 + 1;\nconst c1021 = c1020 + 1;\nconst c1022 = c1021 + 1;\nconst c1023 = c1022 + 1;\nconst c1024 = c1023 + 1;\nconst c1025 = c1024 + 1;\nconst c1026 = c1025 + 1;\nconst c1027 = c1026 + 1;\nconst c1028 = c1027 + 1;\nconst c1029 = c1028 + 1;\nconst c1030 = c1029 + 1;\nconst c1031 = c1030 + 1;\nconst c1032 = c1031 + 1;\nconst c1033 = c1032 + 1;\nconst c1034 = c1033 + 1;\nconst c1035 = c1034 + 1;\nconst c1036 = c1035 + 1;\nconst c1037 = c1036 + 1;\nconst c1038 = c1037 + 1;\nconst c1039 = c1038 + 1;\nconst c1040 = c1039 + 1;\nconst c1041 = c1040 + 1;\nconst c1042 = c1041 + 1;\nconst c1043 = c1042 + 1;\nconst c1044 = c1043 + 1;\nconst c1045 = c1044 + 1;\nconst c1046 = c1045 + 1;\nconst c1047 = c1046 + 1;\nconst c1048 = c1047 + 1;\nconst c1049 = c1048 + 1;\nconst c1050 = c1049 + 1;\nconst c1051 = c1050 + 1;\nconst c1052 = c1051 + 1;\nconst c1053 = c1052 + 1;\nconst c1054 = c1053 + 1;\nconst c1055 = c1054 + 1;\nconst c1056 = c1055 + 1;\nconst c1057 = c1056 + 1;\nconst c1058 = c1057 + 1;\nconst c1059 = c1058 + 1;\nconst c1060 = c1059 + 1;\nconst c1061 = c1060 + 1;\nconst c1062 = c1061 + 1;\nconst c1063 = c1062 + 1;\nconst c1064 = c1063 + 1;\nconst c1065 = c1064 + 1;\nconst c1066 = c1065 + 1;\nconst c1067 = c1066 + 1;\nconst c1068 = c1067 + 1;\nconst c1069 = c1068 + 1;\nconst c1070 = c1069 + 1;\nconst c1071 = c1070 + 1;\nconst c1072 = c1071 + 1;\nconst c1073 = c1072 + 1;\nconst c1074 = c1073 + 1;\nconst c1075 = c1074 + 1;\nconst c1076 = c1075 + 1;\nconst c1077 = c1076 + 1;\nconst c1078 = c1077 + 1;\nconst c1079 = c1078 + 1;\nconst c1080 = c1079 + 1;\nconst c1081 = c1080 + 1;\nconst c1082 = c1081 + 1;\nconst c1083 = c1082 + 1;\nconst c1084 = c1083 + 1;\nconst c1085 = c1084 + 1;\nconst c1086 = c1085 + 1;\nconst c1087 = c1086 + 1;\nconst c1088 = c1087 + 1;\nconst c1089 = c1088 + 1;\nconst c1090 = c1089 + 1;\nconst c1091 = c1090 + 1;\nconst c1092 = c1091 + 1;\nconst c1093 = c1092 + 1;\nconst c1094 = c1093 + 1;\nconst c1095 = c1094 + 1;\nconst c1096 = c1095 + 1;\nconst c1097 = c1096 + 1;\nconst c1098 = c1097 + 1;\nconst c1099 = c1098 + 1;\nconst c1100 = c1099 + 1;\nconst c1101 = c1100 + 1;\nconst c1102 = c1101 + 1;\nconst c1103 = c1102 + 1;\nconst c1104 = c1103 + 1;\nconst c1105 = c1104 + 1;\nconst c1106 = c1105 + 1;\nconst c1107 = c1106 + 1;\nconst c1108 = c1107 + 1;\nconst c1109 = c1108 + 1;\nconst c1110 = c1109 + 1;\nconst c1111 = c1110 + 1;\nconst c1112 = c1111 + 1;\nconst c1113 = c1112 + 1;\nconst c1114 = c1113 + 1;\nconst c1115 = c1114 + 1;\nconst c1116 = c1115 + 1;\nconst c1117 = c1116 + 1;\nconst c1118 = c1117 + 1;\nconst c1119 = c1118 + 1;\nconst c1120 = c1119 + 1;\nconst c1121 = c1120 + 1;\nconst c1122 = c1121 + 1;\nconst c1123 = c1122 + 1;\nconst c1124 = c1123 + 1;\nconst c1125 = c1124 + 1;\nconst c1126 = c1125 + 1;\nconst c1127 = c1126 + 1;\nconst c1128 = c1127 + 1;\nconst c1129 = c1128 + 1;\nconst c1130 = c1129 + 1;\nconst c1131 = c1130 + 1;\nconst c1132 = c1131 + 1;\nconst c1133 = c1132 + 1;\nconst c1134 = c1133 + 1;\nconst c1135 = c1134 + 1;\nconst c1136 = c1135 + 1;\nconst c1137 = c1136 + 1;\nconst c1138 = c1137 + 1;\nconst c1139 = c1138 + 1;\nconst c1140 = c1139 + 1;\nconst c1141 = c1140 + 1;\nconst c1142 = c1141 + 1;\nconst c1143 = c1142 + 1;\nconst c1144 = c1143 + 1;\nconst c1145 = c1144 + 1;\nconst c1146 = c1145 + 1;\nconst c1147 = c1146 + 1;\nconst c1148 = c1147 + 1;\nconst c1149 = c1148 + 1;\nconst c1150 = c1149 + 1;\nconst c1151 = c1150 + 1;\nconst c1152 = c1151 + 1;\nconst c1153 = c1152 + 1;\nconst c1154 = c1153 + 1;\nconst c1155 = c1154 + 1;\nconst c1156 = c1155 + 1;\nconst c1157 = c1156 + 1;\nconst c1158 = c1157 + 1;\nconst c1159 = c1158 + 1;\nconst c1160 = c1159 + 1;\nconst c1161 = c1160 + 1;\nconst c1162 = c1161 + 1;\nconst c1163 = c1162 + 1;\nconst c1164 = c1163 + 1;\nconst c1165 = c1164 + 1;\nconst c1166 = c1165 + 1;\nconst c1167 = c1166 + 1;\nconst c1168 = c1167 + 1;\nconst c1169 = c1168 + 1;\nconst c1170 = c1169 + 1;\nconst c1171 = c1170 + 1;\nconst c1172 = c1171 + 1;\nconst c1173 = c1172 + 1;\nconst c1174 = c1173 + 1;\nconst c1175 = c1174 + 1;\nconst c1176 = c1175 + 1;\nconst c1177 = c1176 + 1;\nconst c1178 = c1177 + 1;\nconst c1179 = c1178 + 1;\nconst c1180 = c1179 + 1;\nconst c1181 = c1180 + 1;\nconst c1182 = c1181 + 1;\nconst c1183 = c1182 + 1;\nconst c1184 = c1183 + 1;\nconst c1185 = c1184 + 1;\nconst c1186 = c1185 + 1;\nconst c1187 = c1186 + 1;\nconst c1188 = c1187 + 1;\nconst c1189 = c1188 + 1;\nconst c1190 = c1189 + 1;\nconst c1191 = c1190 + 1;\nconst c1192 = c1191 + 1;\nconst c1193 = c1192 + 1;\nconst c1194 = c1193 + 1;\nconst c1195 = c1194 + 1;\nconst c1196 = c1195 + 1;\nconst c1197 = c1196 + 1;\nconst c1198 = c1197 + 1;\nconst c1199 = c1198 + 1;\nconst c1200 = c1199 + 1;\nconst c1201 = c1200 + 1;\nconst c1202 = c1201 + 1;\nconst c1203 = c1202 + 1;\nconst c1204 = c1203 + 1;\nconst c1205 = c1204 + 1;\nconst c1206 = c1205 + 1;\nconst c1207 = c1206 + 1;\nconst c1208 = c1207 + 1;\nconst c1209 = c1208 + 1;\nconst c1210 = c1209 + 1;\nconst c1211 = c1210 + 1;\nconst c1212 = c1211 + 1;\nconst c1213 = c1212 + 1;\nconst c1214 = c1213 + 1;\nconst c1215 = c1214 + 1;\nconst c1216 = c1215 + 1;\nconst c1217 = c1216 + 1;\nconst c1218 = c1217 + 1;\nconst c1219 = c1218 + 1;\nconst c1220 = c1219 + 1;\nconst c1221 = c1220 + 1;\nconst c1222 = c1221 + 1;\nconst c1223 = c1222 + 1;\nconst c1224 = c1223 + 1;\nconst c1225 = c1224 + 1;\nconst c1226 = c1225 + 1;\nconst c1227 = c1226 + 1;\nconst c1228 = c1227 + 1;\nconst c1229 = c1228 + 1;\nconst c1230 = c1229 + 1;\nconst c1231 = c1230 + 1;\nconst c1232 = c1231 + 1;\nconst c1233 = c1232 + 1;\nconst c1234 = c1233 + 1;\nconst c1235 = c1234 + 1;\nconst c1236 = c1235 + 1;\nconst c1237 = c1236 + 1;\nconst c1238 = c1237 + 1;\nconst c1239 = c1238 + 1;\nconst c1240 = c1239 + 1;\nconst c1241 = c1240 + 1;\nconst c1242 = c1241 + 1;\nconst c1243 = c1242 + 1;\nconst c1244 = c1243 + 1;\nconst c1245 = c1244 + 1;\nconst c1246 = c1245 + 1;\nconst c1247 = c1246 + 1;\nconst c1248 = c1247 + 1;\nconst c1249 = c1248 + 1;\nconst c1250 = c1249 + 1;\nconst c1251 = c1250 + 1;\nconst c1252 = c1251 + 1;\nconst c1253 = c1252 + 1;\nconst c1254 = c1253 + 1;\nconst c1255 = c1254 + 1;\nconst c1256 = c1255 + 1;\nconst c1257 = c1256 + 1;\nconst c1258 = c1257 + 1;\nconst c1259 = c1258 + 1;\nconst c1260 = c1259 + 1;\nconst c1261 = c1260 + 1;\nconst c1262 = c1261 + 1;\nconst c1263 = c1262 + 1;\nconst c1264 = c1263 + 1;\nconst c1265 = c1264 + 1;\nconst c1266 = c1265 + 1;\nconst c1267 = c1266 + 1;\nconst c1268 = c1267 + 1;\nconst c1269 = c1268 + 1;\nconst c1270 = c1269 + 1;\nconst c1271 = c1270 + 1;\nconst c1272 = c1271 + 1;\nconst c1273 = c1272 + 1;\nconst c1274 = c1273 + 1;\nconst c1275 = c1274 + 1;\nconst c1276 = c1275 + 1;\nconst c1277 = c1276 + 1;\nconst c1278 = c1277 + 1;\nconst c1279 = c1278 + 1;\nconst c1280 = c1279 + 1;\nconst c1281 = c1280 + 1;\nconst c1282 = c1281 + 1;\nconst c1283 = c1282 + 1;\nconst c1284 = c1283 + 1;\nconst c1285 = c1284 + 1;\nconst c1286 = c1285 + 1;\nconst c1287 = c1286 + 1;\nconst c1288 = c1287 + 1;\nconst c1289 = c1288 + 1;\nconst c1290 = c1289 + 1;\nconst c1291 = c1290 + 1;\nconst c1292 = c1291 + 1;\nconst c1293 = c1292 + 1;\nconst c1294 = c1293 + 1;\nconst c1295 = c1294 + 1;\nconst c1296 = c1295 + 1;\nconst c1297 = c1296 + 1;\nconst c1298 = c1297 + 1;\nconst c1299 = c1298 + 1;\nconst c1300 = c1299 + 1;\nconst c1301 = c1300 + 1;\nconst c1302 = c1301 + 1;\nconst c1303 = c1302 + 1;\nconst c1304 = c1303 + 1;\nconst c1305 = c1304 + 1;\nconst c1306 = c1305 + 1;\nconst c1307 = c1306 + 1;\nconst c1308 = c1307 + 1;\nconst c1309 = c1308 + 1;\nconst c1310 = c1309 + 1;\nconst c1311 = c1310 + 1;\nconst c1312 = c1311 + 1;\nconst c1313 = c1312 + 1;\nconst c1314 = c1313 + 1;\nconst c1315 = c1314 + 1;\nconst c1316 = c1315 + 1;\nconst c1317 = c1316 + 1;\nconst c1318 = c1317 + 1;\nconst c1319 = c1318 + 1;\nconst c1320 = c1319 + 1;\nconst c1321 = c1320 + 1;\nconst c1322 = c1321 + 1;\nconst c1323 = c1322 + 1;\nconst c1324 = c1323 + 1;\nconst c1325 = c1324 + 1;\nconst c1326 = c1325 + 1;\nconst c1327 = c1326 + 1;\nconst c1328 = c1327 + 1;\nconst c1329 = c1328 + 1;\nconst c1330 = c1329 + 1;\nconst c1331 = c1330 + 1;\nconst c1332 = c1331 + 1;\nconst c1333 = c1332 + 1;\nconst c1334 = c1333 + 1;\nconst c1335 = c1334 + 1;\nconst c1336 = c1335 + 1;\nconst c1337 = c1336 + 1;\nconst c1338 = c1337 + 1;\nconst c1339 = c1338 + 1;\nconst c1340 = c1339 + 1;\nconst c1341 = c1340 + 1;\nconst c1342 = c1341 + 1;\nconst c1343 = c1342 + 1;\nconst c1344 = c1343 + 1;\nconst c1345 = c1344 + 1;\nconst c1346 = c1345 + 1;\nconst c1347 = c1346 + 1;\nconst c1348 = c1347 + 1;\nconst c1349 = c1348 + 1;\nconst c1350 = c1349 + 1;\nconst c1351 = c1350 + 1;\nconst c1352 = c1351 + 1;\nconst c1353 = c1352 + 1;\nconst c1354 = c1353 + 1;\nconst c1355 = c1354 + 1;\nconst c1356 = c1355 + 1;\nconst c1357 = c1356 + 1;\nconst c1358 = c1357 + 1;\nconst c1359 = c1358 + 1;\nconst c1360 = c1359 + 1;\nconst c1361 = c1360 + 1;\nconst c1362 = c1361 + 1;\nconst c1363 = c1362 + 1;\nconst c1364 = c1363 + 1;\nconst c1365 = c1364 + 1;\nconst c1366 = c1365 + 1;\nconst c1367 = c1366 + 1;\nconst c1368 = c1367 + 1;\nconst c1369 = c1368 + 1;\nconst c1370 = c1369 + 1;\nconst c1371 = c1370 + 1;\nconst c1372 = c1371 + 1;\nconst c1373 = c1372 + 1;\nconst c1374 = c1373 + 1;\nconst c1375 = c1374 + 1;\nconst c1376 = c1375 + 1;\nconst c1377 = c1376 + 1;\nconst c1378 = c1377 + 1;\nconst c1379 = c1378 + 1;\nconst c1380 = c1379 + 1;\nconst c1381 = c1380 + 1;\nconst c1382 = c1381 + 1;\nconst c1383 = c1382 + 1;\nconst c1384 = c1383 + 1;\nconst c1385 = c1384 + 1;\nconst c1386 = c1385 + 1;\nconst c1387 = c1386 + 1;\nconst c1388 = c1387 + 1;\nconst c1389 = c1388 + 1;\nconst c1390 = c1389 + 1;\nconst c1391 = c1390 + 1;\nconst c1392 = c1391 + 1;\nconst c1393 = c1392 + 1;\nconst c1394 = c1393 + 1;\nconst c1395 = c1394 + 1;\nconst c1396 = c1395 + 1;\nconst c1397 = c1396 + 1;\nconst c1398 = c1397 + 1;\nconst c1399 = c1398 + 1;\nconst c1400 = c1399 + 1;\nconst c1401 = c1400 + 1;\nconst c1402 = c1401 + 1;\nconst c1403 = c1402 + 1;\nconst c1404 = c1403 + 1;\nconst c1405 = c1404 + 1;\nconst c1406 = c1405 + 1;\nconst c1407 = c1406 + 1;\nconst c1408 = c1407 + 1;\nconst c1409 = c1408 + 1;\nconst c1410 = c1409 + 1;\nconst c1411 = c1410 + 1;\nconst c1412 = c1411 + 1;\nconst c1413 = c1412 + 1;\nconst c1414 = c1413 + 1;\nconst c1415 = c1414 + 1;\nconst c1416 = c1415 + 1;\nconst c1417 = c1416 + 1;\nconst c1418 = c1417 + 1;\nconst c1419 = c1418 + 1;\nconst c1420 = c1419 + 1;\nconst c1421 = c1420 + 1;\nconst c1422 = c1421 + 1;\nconst c1423 = c1422 + 1;\nconst c1424 = c1423 + 1;\nconst c1425 = c1424 + 1;\nconst c1426 = c1425 + 1;\nconst c1427 = c1426 + 1;\nconst c1428 = c1427 + 1;\nconst c1429 = c1428 + 1;\nconst c1430 = c1429 + 1;\nconst c1431 = c1430 + 1;\nconst c1432 = c1431 + 1;\nconst c1433 = c1432 + 1;\nconst c1434 = c1433 + 1;\nconst c1435 = c1434 + 1;\nconst c1436 = c1435 + 1;\nconst c1437 = c1436 + 1;\nconst c1438 = c1437 + 1;\nconst c1439 = c1438 + 1;\nconst c1440 = c1439 + 1;\nconst c1441 = c1440 + 1;\nconst c1442 = c1441 + 1;\nconst c1443 = c1442 + 1;\nconst c1444 = c1443 + 1;\nconst c1445 = c1444 + 1;\nconst c1446 = c1445 + 1;\nconst c1447 = c1446 + 1;\nconst c1448 = c1447 + 1;\nconst c1449 = c1448 + 1;\nconst c1450 = c1449 + 1;\nconst c1451 = c1450 + 1;\nconst c1452 = c1451 + 1;\nconst c1453 = c1452 + 1;\nconst c1454 = c1453 + 1;\nconst c1455 = c1454 + 1;\nconst c1456 = c1455 + 1;\nconst c1457 = c1456 + 1;\nconst c1458 = c1457 + 1;\nconst c1459 = c1458 + 1;\nconst c1460 = c1459 + 1;\nconst c1461 = c1460 + 1;\nconst c1462 = c1461 + 1;\nconst c1463 = c1462 + 1;\nconst c1464 = c1463 + 1;\nconst c1465 = c1464 + 1;\nconst c1466 = c1465 + 1;\nconst c1467 = c1466 + 1;\nconst c1468 = c1467 + 1;\nconst c1469 = c1468 + 1;\nconst c1470 = c1469 + 1;\nconst c1471 = c1470 + 1;\nconst c1472 = c1471 + 1;\nconst c1473 = c1472 + 1;\nconst c1474 = c1473 + 1;\nconst c1475 = c1474 + 1;\nconst c1476 = c1475 + 1;\nconst c1477 = c1476 + 1;\nconst c1478 = c1477 + 1;\nconst c1479 = c1478 + 1;\nconst c1480 = c1479 + 1;\nconst c1481 = c1480 + 1;\nconst c1482 = c1481 + 1;\nconst c1483 = c1482 + 1;\nconst c1484 = c1483 + 1;\nconst c1485 = c1484 + 1;\nconst c1486 = c1485 + 1;\nconst c1487 = c1486 + 1;\nconst c1488 = c1487 + 1;\nconst c1489 = c1488 + 1;\nconst c1490 = c1489 + 1;\nconst c1491 = c1490 + 1;\nconst c1492 = c1491 + 1;\nconst c1493 = c1492 + 1;\nconst c1494 = c1493 + 1;\nconst c1495 = c1494 + 1;\nconst c1496 = c1495 + 1;\nconst c1497 = c1496 + 1;\nconst c1498 = c1497 + 1;\nconst c1499 = c1498 + 1;\nconst c1500 = c1499 + 1;\nconst c1501 = c1500 + 1;\nconst c1502 = c1501 + 1;\nconst c1503 = c1502 + 1;\nconst c1504 = c1503 + 1;\nconst c1505 = c1504 + 1;\nconst c1506 = c1505 + 1;\nconst c1507 = c1506 + 1;\nconst c1508 = c1507 + 1;\nconst c1509 = c1508 + 1;\nconst c1510 = c1509 + 1;\nconst c1511 = c1510 + 1;\nconst c1512 = c1511 + 1;\nconst c1513 = c1512 + 1;\nconst c1514 = c1513 + 1;\nconst c1515 = c1514 + 1;\nconst c1516 = c1515 + 1;\nconst c1517 = c1516 + 1;\nconst c1518 = c1517 + 1;\nconst c1519 = c1518 + 1;\nconst c1520 = c1519 + 1;\nconst c1521 = c1520 + 1;\nconst c1522 = c1521 + 1;\nconst c1523 = c1522 + 1;\nconst c1524 = c1523 + 1;\nconst c1525 = c1524 + 1;\nconst c1526 = c1525 + 1;\nconst c1527 = c1526 + 1;\nconst c1528 = c1527 + 1;\nconst c1529 = c1528 + 1;\nconst c1530 = c1529 + 1;\nconst c1531 = c1530 + 1;\nconst c1532 = c1531 + 1;\nconst c1533 = c1532 + 1;\nconst c1534 = c1533 + 1;\nconst c1535 = c1534 + 1;\nconst c1536 = c1535 + 1;\nconst c1537 = c1536 + 1;\nconst c1538 = c1537 + 1;\nconst c1539 = c1538 + 1;\nconst c1540 = c1539 + 1;\nconst c1541 = c1540 + 1;\nconst c1542 = c1541 + 1;\nconst c1543 = c1542 + 1;\nconst c1544 = c1543 + 1;\nconst c1545 = c1544 + 1;\nconst c1546 = c1545 + 1;\nconst c1547 = c1546 + 1;\nconst c1548 = c1547 + 1;\nconst c1549 = c1548 + 1;\nconst c1550 = c1549 + 1;\nconst c1551 = c1550 + 1;\nconst c1552 = c1551 + 1;\nconst c1553 = c1552 + 1;\nconst c1554 = c1553 + 1;\nconst c1555 = c1554 + 1;\nconst c1556 = c1555 + 1;\nconst c1557 = c1556 + 1;\nconst c1558 = c1557 + 1;\nconst c1559 = c1558 + 1;\nconst c1560 = c1559 + 1;\nconst c1561 = c1560 + 1;\nconst c1562 = c1561 + 1;\nconst c1563 = c1562 + 1;\nconst c1564 = c1563 + 1;\nconst c1565 = c1564 + 1;\nconst c1566 = c1565 + 1;\nconst c1567 = c1566 + 1;\nconst c1568 = c1567 + 1;\nconst c1569 = c1568 + 1;\nconst c1570 = c1569 + 1;\nconst c1571 = c1570 + 1;\nconst c1572 = c1571 + 1;\nconst c1573 = c1572 + 1;\nconst c1574 = c1573 + 1;\nconst c1575 = c1574 + 1;\nconst c1576 = c1575 + 1;\nconst c1577 = c1576 + 1;\nconst c1578 = c1577 + 1;\nconst c1579 = c1578 + 1;\nconst c1580 = c1579 + 1;\nconst c1581 = c1580 + 1;\nconst c1582 = c1581 + 1;\nconst c1583 = c1582 + 1;\nconst c1584 = c1583 + 1;\nconst c1585 = c1584 + 1;\nconst c1586 = c1585 + 1;\nconst c1587 = c1586 + 1;\nconst c1588 = c1587 + 1;\nconst c1589 = c1588 + 1;\nconst c1590 = c1589 + 1;\nconst c1591 = c1590 + 1;\nconst c1592 = c1591 + 1;\nconst c1593 = c1592 + 1;\nconst c1594 = c1593 + 1;\nconst c1595 = c1594 + 1;\nconst c1596 = c1595 + 1;\nconst c1597 = c1596 + 1;\nconst c1598 = c1597 + 1;\nconst c1599 = c1598 + 1;\nconst c1600 = c1599 + 1;\nconst c1601 = c1600 + 1;\nconst c1602 = c1601 + 1;\nconst c1603 = c1602 + 1;\nconst c1604 = c1603 + 1;\nconst c1605 = c1604 + 1;\nconst c1606 = c1605 + 1;\nconst c1607 = c1606 + 1;\nconst c1608 = c1607 + 1;\nconst c1609 = c1608 + 1;\nconst c1610 = c1609 + 1;\nconst c1611 = c1610 + 1;\nconst c1612 = c1611 + 1;\nconst c1613 = c1612 + 1;\nconst c1614 = c1613 + 1;\nconst c1615 = c1614 + 1;\nconst c1616 = c1615 + 1;\nconst c1617 = c1616 + 1;\nconst c1618 = c1617 + 1;\nconst c1619 = c1618 + 1;\nconst c1620 = c1619 + 1;\nconst c1621 = c1620 + 1;\nconst c1622 = c1621 + 1;\nconst c1623 = c1622 + 1;\nconst c1624 = c1623 + 1;\nconst c1625 = c1624 + 1;\nconst c1626 = c1625 + 1;\nconst c1627 = c1626 + 1;\nconst c1628 = c1627 + 1;\nconst c1629 = c1628 + 1;\nconst c1630 = c1629 + 1;\nconst c1631 = c1630 + 1;\nconst c1632 = c1631 + 1;\nconst c1633 = c1632 + 1;\nconst c1634 = c1633 + 1;\nconst c1635 = c1634 + 1;\nconst c1636 = c1635 + 1;\nconst c1637 = c1636 + 1;\nconst c1638 = c1637 + 1;\nconst c1639 = c1638 + 1;\nconst c1640 = c1639 + 1;\nconst c1641 = c1640 + 1;\nconst c1642 = c1641 + 1;\nconst c1643 = c1642 + 1;\nconst c1644 = c1643 + 1;\nconst c1645 = c1644 + 1;\nconst c1646 = c1645 + 1;\nconst c1647 = c1646 + 1;\nconst c1648 = c1647 + 1;\nconst c1649 = c1648 + 1;\nconst c1650 = c1649 + 1;\nconst c1651 = c1650 + 1;\nconst c1652 = c1651 + 1;\nconst c1653 = c1652 + 1;\nconst c1654 = c1653 + 1;\nconst c1655 = c1654 + 1;\nconst c1656 = c1655 + 1;\nconst c1657 = c1656 + 1;\nconst c1658 = c1657 + 1;\nconst c1659 = c1658 + 1;\nconst c1660 = c1659 + 1;\nconst c1661 = c1660 + 1;\nconst c1662 = c1661 + 1;\nconst c1663 = c1662 + 1;\nconst c1664 = c1663 + 1;\nconst c1665 = c1664 + 1;\nconst c1666 = c1665 + 1;\nconst c1667 = c1666 + 1;\nconst c1668 = c1667 + 1;\nconst c1669 = c1668 + 1;\nconst c1670 = c1669 + 1;\nconst c1671 = c1670 + 1;\nconst c1672 = c1671 + 1;\nconst c1673 = c1672 + 1;\nconst c1674 = c1673 + 1;\nconst c1675 = c1674 + 1;\nconst c1676 = c1675 + 1;\nconst c1677 = c1676 + 1;\nconst c1678 = c1677 + 1;\nconst c1679 = c1678 + 1;\nconst c1680 = c1679 + 1;\nconst c1681 = c1680 + 1;\nconst c1682 = c1681 + 1;\nconst c1683 = c1682 + 1;\nconst c1684 = c1683 + 1;\nconst c1685 = c1684 + 1;\nconst c1686 = c1685 + 1;\nconst c1687 = c1686 + 1;\nconst c1688 = c1687 + 1;\nconst c1689 = c1688 + 1;\nconst c1690 = c1689 + 1;\nconst c1691 = c1690 + 1;\nconst c1692 = c1691 + 1;\nconst c1693 = c1692 + 1;\nconst c1694 = c1693 + 1;\nconst c1695 = c1694 + 1;\nconst c1696 = c1695 + 1;\nconst c1697 = c1696 + 1;\nconst c1698 = c1697 + 1;\nconst c1699 = c1698 + 1;\nconst c1700 = c1699 + 1;\nconst c1701 = c1700 + 1;\nconst c1702 = c1701 + 1;\nconst c1703 = c1702 + 1;\nconst c1704 = c1703 + 1;\nconst c1705 = c1704 + 1;\nconst c1706 = c1705 + 1;\nconst c1707 = c1706 + 1;\nconst c1708 = c1707 + 1;\nconst c1709 = c1708 + 1;\nconst c1710 = c1709 + 1;\nconst c1711 = c1710 + 1;\nconst c1712 = c1711 + 1;\nconst c1713 = c1712 + 1;\nconst c1714 = c1713 + 1;\nconst c1715 = c1714 + 1;\nconst c1716 = c1715 + 1;\nconst c1717 = c1716 + 1;\nconst c1718 = c1717 + 1;\nconst c1719 = c1718 + 1;\nconst c1720 = c1719 + 1;\nconst c1721 = c1720 + 1;\nconst c1722 = c1721 + 1;\nconst c1723 = c1722 + 1;\nconst c1724 = c1723 + 1;\nconst c1725 = c1724 + 1;\nconst c1726 = c1725 + 1;\nconst c1727 = c1726 + 1;\nconst c1728 = c1727 + 1;\nconst c1729 = c1728 + 1;\nconst c1730 = c1729 + 1;\nconst c1731 = c1730 + 1;\nconst c1732 = c1731 + 1;\nconst c1733 = c1732 + 1;\nconst c1734 = c1733 + 1;\nconst c1735 = c1734 + 1;\nconst c1736 = c1735 + 1;\nconst c1737 = c1736 + 1;\nconst c1738 = c1737 + 1;\nconst c1739 = c1738 + 1;\nconst c1740 = c1739 + 1;\nconst c1741 = c1740 + 1;\nconst c1742 = c1741 + 1;\nconst c1743 = c1742 + 1;\nconst c1744 = c1743 + 1;\nconst c1745 = c1744 + 1;\nconst c1746 = c1745 + 1;\nconst c1747 = c1746 + 1;\nconst c1748 = c1747 + 1;\nconst c1749 = c1748 + 1;\nconst c1750 = c1749 + 1;\nconst c1751 = c1750 + 1;\nconst c1752 = c1751 + 1;\nconst c1753 = c1752 + 1;\nconst c1754 = c1753 + 1;\nconst c1755 = c1754 + 1;\nconst c1756 = c1755 + 1;\nconst c1757 = c1756 + 1;\nconst c1758 = c1757 + 1;\nconst c1759 = c1758 + 1;\nconst c1760 = c1759 + 1;\nconst c1761 = c1760 + 1;\nconst c1762 = c1761 + 1;\nconst c1763 = c1762 + 1;\nconst c1764 = c1763 + 1;\nconst c1765 = c1764 + 1;\nconst c1766 = c1765 + 1;\nconst c1767 = c1766 + 1;\nconst c1768 = c1767 + 1;\nconst c1769 = c1768 + 1;\nconst c1770 = c1769 + 1;\nconst c1771 = c1770 + 1;\nconst c1772 = c1771 + 1;\nconst c1773 = c1772 + 1;\nconst c1774 = c1773 + 1;\nconst c1775 = c1774 + 1;\nconst c1776 = c1775 + 1;\nconst c1777 = c1776 + 1;\nconst c1778 = c1777 + 1;\nconst c1779 = c1778 + 1;\nconst c1780 = c1779 + 1;\nconst c1781 = c1780 + 1;\nconst c1782 = c1781 + 1;\nconst c1783 = c1782 + 1;\nconst c1784 = c1783 + 1;\nconst c1785 = c1784 + 1;\nconst c1786 = c1785 + 1;\nconst c1787 = c1786 + 1;\nconst c1788 = c1787 + 1;\nconst c1789 = c1788 + 1;\nconst c1790 = c1789 + 1;\nconst c1791 = c1790 + 1;\nconst c1792 = c1791 + 1;\nconst c1793 = c1792 + 1;\nconst c1794 = c1793 + 1;\nconst c1795 = c1794 + 1;\nconst c1796 = c1795 + 1;\nconst c1797 = c1796 + 1;\nconst c1798 = c1797 + 1;\nconst c1799 = c1798 + 1;\nconst c1800 = c1799 + 1;\nconst c1801 = c1800 + 1;\nconst c1802 = c1801 + 1;\nconst c1803 = c1802 + 1;\nconst c1804 = c1803 + 1;\nconst c1805 = c1804 + 1;\nconst c1806 = c1805 + 1;\nconst c1807 = c1806 + 1;\nconst c1808 = c1807 + 1;\nconst c1809 = c1808 + 1;\nconst c1810 = c1809 + 1;\nconst c1811 = c1810 + 1;\nconst c1812 = c1811 + 1;\nconst c1813 = c1812 + 1;\nconst c1814 = c1813 + 1;\nconst c1815 = c1814 + 1;\nconst c1816 = c1815 + 1;\nconst c1817 = c1816 + 1;\nconst c1818 = c1817 + 1;\nconst c1819 = c1818 + 1;\nconst c1820 = c1819 + 1;\nconst c1821 = c1820 + 1;\nconst c1822 = c1821 + 1;\nconst c1823 = c1822 + 1;\nconst c1824 = c1823 + 1;\nconst c1825 = c1824 + 1;\nconst c1826 = c1825 + 1;\nconst c1827 = c1826 + 1;\nconst c1828 = c1827 + 1;\nconst c1829 = c1828 + 1;\nconst c1830 = c1829 + 1;\nconst c1831 = c1830 + 1;\nconst c1832 = c1831 + 1;\nconst c1833 = c1832 + 1;\nconst c1834 = c1833 + 1;\nconst c1835 = c1834 + 1;\nconst c1836 = c1835 + 1;\nconst c1837 = c1836 + 1;\nconst c1838 = c1837 + 1;\nconst c1839 = c1838 + 1;\nconst c1840 = c1839 + 1;\nconst c1841 = c1840 + 1;\nconst c1842 = c1841 + 1;\nconst c1843 = c1842 + 1;\nconst c1844 = c1843 + 1;\nconst c1845 = c1844 + 1;\nconst c1846 = c1845 + 1;\nconst c1847 = c1846 + 1;\nconst c1848 = c1847 + 1;\nconst c1849 = c1848 + 1;\nconst c1850 = c1849 + 1;\nconst c1851 = c1850 + 1;\nconst c1852 = c1851 + 1;\nconst c1853 = c1852 + 1;\nconst c1854 = c1853 + 1;\nconst c1855 = c1854 + 1;\nconst c1856 = c1855 + 1;\nconst c1857 = c1856 + 1;\nconst c1858 = c1857 + 1;\nconst c1859 = c1858 + 1;\nconst c1860 = c1859 + 1;\nconst c1861 = c1860 + 1;\nconst c1862 = c1861 + 1;\nconst c1863 = c1862 + 1;\nconst c1864 = c1863 + 1;\nconst c1865 = c1864 + 1;\nconst c1866 = c1865 + 1;\nconst c1867 = c1866 + 1;\nconst c1868 = c1867 + 1;\nconst c1869 = c1868 + 1;\nconst c1870 = c1869 + 1;\nconst c1871 = c1870 + 1;\nconst c1872 = c1871 + 1;\nconst c1873 = c1872 + 1;\nconst c1874 = c1873 + 1;\nconst c1875 = c1874 + 1;\nconst c1876 = c1875 + 1;\nconst c1877 = c1876 + 1;\nconst c1878 = c1877 + 1;\nconst c1879 = c1878 + 1;\nconst c1880 = c1879 + 1;\nconst c1881 = c1880 + 1;\nconst c1882 = c1881 + 1;\nconst c1883 = c1882 + 1;\nconst c1884 = c1883 + 1;\nconst c1885 = c1884 + 1;\nconst c1886 = c1885 + 1;\nconst c1887 = c1886 + 1;\nconst c1888 = c1887 + 1;\nconst c1889 = c1888 + 1;\nconst c1890 = c1889 + 1;\nconst c1891 = c1890 + 1;\nconst c1892 = c1891 + 1;\nconst c1893 = c1892 + 1;\nconst c1894 = c1893 + 1;\nconst c1895 = c1894 + 1;\nconst c1896 = c1895 + 1;\nconst c1897 = c1896 + 1;\nconst c1898 = c1897 + 1;\nconst c1899 = c1898 + 1;\nconst c1900 = c1899 + 1;\nconst c1901 = c1900 + 1;\nconst c1902 = c1901 + 1;\nconst c1903 = c1902 + 1;\nconst c1904 = c1903 + 1;\nconst c1905 = c1904 + 1;\nconst c1906 = c1905 + 1;\nconst c1907 = c1906 + 1;\nconst c1908 = c1907 + 1;\nconst c1909 = c1908 + 1;\nconst c1910 = c1909 + 1;\nconst c1911 = c1910 + 1;\nconst c1912 = c1911 + 1;\nconst c1913 = c1912 + 1;\nconst c1914 = c1913 + 1;\nconst c1915 = c1914 + 1;\nconst c1916 = c1915 + 1;\nconst c1917 = c1916 + 1;\nconst c1918 = c1917 + 1;\nconst c1919 = c1918 + 1;\nconst c1920 = c1919 + 1;\nconst c1921 = c1920 + 1;\nconst c1922 = c1921 + 1;\nconst c1923 = c1922 + 1;\nconst c1924 = c1923 + 1;\nconst c1925 = c1924 + 1;\nconst c1926 = c1925 + 1;\nconst c1927 = c1926 + 1;\nconst c1928 = c1927 + 1;\nconst c1929 = c1928 + 1;\nconst c1930 = c1929 + 1;\nconst c1931 = c1930 + 1;\nconst c1932 = c1931 + 1;\nconst c1933 = c1932 + 1;\nconst c1934 = c1933 + 1;\nconst c1935 = c1934 + 1;\nconst c1936 = c1935 + 1;\nconst c1937 = c1936 + 1;\nconst c1938 = c1937 + 1;\nconst c1939 = c1938 + 1;\nconst c1940 = c1939 + 1;\nconst c1941 = c1940 + 1;\nconst c1942 = c1941 + 1;\nconst c1943 = c1942 + 1;\nconst c1944 = c1943 + 1;\nconst c1945 = c1944 + 1;\nconst c1946 = c1945 + 1;\nconst c1947 = c1946 + 1;\nconst c1948 = c1947 + 1;\nconst c1949 = c1948 + 1;\nconst c1950 = c1949 + 1;\nconst c1951 = c1950 + 1;\nconst c1952 = c1951 + 1;\nconst c1953 = c1952 + 1;\nconst c1954 = c1953 + 1;\nconst c1955 = c1954 + 1;\nconst c1956 = c1955 + 1;\nconst c1957 = c1956 + 1;\nconst c1958 = c1957 + 1;\nconst c1959 = c1958 + 1;\nconst c1960 = c1959 + 1;\nconst c1961 = c1960 + 1;\nconst c1962 = c1961 + 1;\nconst c1963 = c1962 + 1;\nconst c1964 = c1963 + 1;\nconst c1965 = c1964 + 1;\nconst c1966 = c1965 + 1;\nconst c1967 = c1966 + 1;\nconst c1968 = c1967 + 1;\nconst c1969 = c1968 + 1;\nconst c1970 = c1969 + 1;\nconst c1971 = c1970 + 1;\nconst c1972 = c1971 + 1;\nconst c1973 = c1972 + 1;\nconst c1974 = c1973 + 1;\nconst c1975 = c1974 + 1;\nconst c1976 = c1975 + 1;\nconst c1977 = c1976 + 1;\nconst c1978 = c1977 + 1;\nconst c1979 = c1978 + 1;\nconst c1980 = c1979 + 1;\nconst c1981 = c1980 + 1;\nconst c1982 = c1981 + 1;\nconst c1983 = c1982 + 1;\nconst c1984 = c1983 + 1;\nconst c1985 = c1984 + 1;\nconst c1986 = c1985 + 1;\nconst c1987 = c1986 + 1;\nconst c1988 = c1987 + 1;\nconst c1989 = c1988 + 1;\nconst c1990 = c1989 + 1;\nconst c1991 = c1990 + 1;\nconst c1992 = c1991 + 1;\nconst c1993 = c1992 + 1;\nconst c1994 = c1993 + 1;\nconst c1995 = c1994 + 1;\nconst c1996 = c1995 + 1;\nconst c1997 = c1996 + 1;\nconst c1998 = c1997 + 1;\nconst c1999 = c1998 + 1;\nconst c2000 = c1999 + 1;\nconst c2001 = c2000 + 1;\nconst c2002 = c2001 + 1;\nconst c2003 = c2002 + 1;\nconst c2004 = c2003 + 1;\nconst c2005 = c2004 + 1;\nconst c2006 = c2005 + 1;\nconst c2007 = c2006 + 1;\nconst c2008 = c2007 + 1;\nconst c2009 = c2008 + 1;\nconst c2010 = c2009 + 1;\nconst c2011 = c2010 + 1;\nconst c2012 = c2011 + 1;\nconst c2013 = c2012 + 1;\nconst c2014 = c2013 + 1;\nconst c2015 = c2014 + 1;\nconst c2016 = c2015 + 1;\nconst c2017 = c2016 + 1;\nconst c2018 = c2017 + 1;\nconst c2019 = c2018 + 1;\nconst c2020 = c2019 + 1;\nconst c2021 = c2020 + 1;\nconst c2022 = c2021 + 1;\nconst c2023 = c2022 + 1;\nconst c2024 = c2023 + 1;\nconst c2025 = c2024 + 1;\nconst c2026 = c2025 + 1;\nconst c2027 = c2026 + 1;\nconst c2028 = c2027 + 1;\nconst c2029 = c2028 + 1;\nconst c2030 = c2029 + 1;\nconst c2031 = c2030 + 1;\nconst c2032 = c2031 + 1;\nconst c2033 = c2032 + 1;\nconst c2034 = c2033 + 1;\nconst c2035 = c2034 + 1;\nconst c2036 = c2035 + 1;\nconst c2037 = c2036 + 1;\nconst c2038 = c2037 + 1;\nconst c2039 = c2038 + 1;\nconst c2040 = c2039 + 1;\nconst c2041 = c2040 + 1;\nconst c2042 = c2041 + 1;\nconst c2043 = c2042 + 1;\nconst c2044 = c2043 + 1;\nconst c2045 = c2044 + 1;\nconst c2046 = c2045 + 1;\nconst c2047 = c2046 + 1;\nconst c2048 = c2047 + 1;\nconst c2049 = c2048 + 1;\nconst c2050 = c2049 + 1;\nconst c2051 = c2050 + 1;\nconst c2052 = c2051 + 1;\nconst c2053 = c2052 + 1;\nconst c2054 = c2053 + 1;\nconst c2055 = c2054 + 1;\nconst c2056 = c2055 + 1;\nconst c2057 = c2056 + 1;\nconst c2058 = c2057 + 1;\nconst c2059 = c2058 + 1;\nconst c2060 = c2059 + 1;\nconst c2061 = c2060 + 1;\nconst c2062 = c2061 + 1;\nconst c2063 = c2062 + 1;\nconst c2064 = c2063 + 1;\nconst c2065 = c2064 + 1;\nconst c2066 = c2065 + 1;\nconst c2067 = c2066 + 1;\nconst c2068 = c2067 + 1;\nconst c2069 = c2068 + 1;\nconst c2070 = c2069 + 1;\nconst c2071 = c2070 + 1;\nconst c2072 = c2071 + 1;\nconst c2073 = c2072 + 1;\nconst c2074 = c2073 + 1;\nconst c2075 = c2074 + 1;\nconst c2076 = c2075 + 1;\nconst c2077 = c2076 + 1;\nconst c2078 = c2077 + 1;\nconst c2079 = c2078 + 1;\nconst c2080 = c2079 + 1;\nconst c2081 = c2080 + 1;\nconst c2082 = c2081 + 1;\nconst c2083 = c2082 + 1;\nconst c2084 = c2083 + 1;\nconst c2085 = c2084 + 1;\nconst c2086 = c2085 + 1;\nconst c2087 = c2086 + 1;\nconst c2088 = c2087 + 1;\nconst c2089 = c2088 + 1;\nconst c2090 = c2089 + 1;\nconst c2091 = c2090 + 1;\nconst c2092 = c2091 + 1;\nconst c2093 = c2092 + 1;\nconst c2094 = c2093 + 1;\nconst c2095 = c2094 + 1;\nconst c2096 = c2095 + 1;\nconst c2097 = c2096 + 1;\nconst c2098 = c2097 + 1;\nconst c2099 = c2098 + 1;\nconst c2100 = c2099 + 1;\nconst c2101 = c2100 + 1;\nconst c2102 = c2101 + 1;\nconst c2103 = c2102 + 1;\nconst c2104 = c2103 + 1;\nconst c2105 = c2104 + 1;\nconst c2106 = c2105 + 1;\nconst c2107 = c2106 + 1;\nconst c2108 = c2107 + 1;\nconst c2109 = c2108 + 1;\nconst c2110 = c2109 + 1;\nconst c2111 = c2110 + 1;\nconst c2112 = c2111 + 1;\nconst c2113 = c2112 + 1;\nconst c2114 = c2113 + 1;\nconst c2115 = c2114 + 1;\nconst c2116 = c2115 + 1;\nconst c2117 = c2116 + 1;\nconst c2118 = c2117 + 1;\nconst c2119 = c2118 + 1;\nconst c2120 = c2119 + 1;\nconst c2121 = c2120 + 1;\nconst c2122 = c2121 + 1;\nconst c2123 = c2122 + 1;\nconst c2124 = c2123 + 1;\nconst c2125 = c2124 + 1;\nconst c2126 = c2125 + 1;\nconst c2127 = c2126 + 1;\nconst c2128 = c2127 + 1;\nconst c2129 = c2128 + 1;\nconst c2130 = c2129 + 1;\nconst c2131 = c2130 + 1;\nconst c2132 = c2131 + 1;\nconst c2133 = c2132 + 1;\nconst c2134 = c2133 + 1;\nconst c2135 = c2134 + 1;\nconst c2136 = c2135 + 1;\nconst c2137 = c2136 + 1;\nconst c2138 = c2137 + 1;\nconst c2139 = c2138 + 1;\nconst c2140 = c2139 + 1;\nconst c2141 = c2140 + 1;\nconst c2142 = c2141 + 1;\nconst c2143 = c2142 + 1;\nconst c2144 = c2143 + 1;\nconst c2145 = c2144 + 1;\nconst c2146 = c2145 + 1;\nconst c2147 = c2146 + 1;\nconst c2148 = c2147 + 1;\nconst c2149 = c2148 + 1;\nconst c2150 = c2149 + 1;\nconst c2151 = c2150 + 1;\nconst c2152 = c2151 + 1;\nconst c2153 = c2152 + 1;\nconst c2154 = c2153 + 1;\nconst c2155 = c2154 + 1;\nconst c2156 = c2155 + 1;\nconst c2157 = c2156 + 1;\nconst c2158 = c2157 + 1;\nconst c2159 = c2158 + 1;\nconst c2160 = c2159 + 1;\nconst c2161 = c2160 + 1;\nconst c2162 = c2161 + 1;\nconst c2163 = c2162 + 1;\nconst c2164 = c2163 + 1;\nconst c2165 = c2164 + 1;\nconst c2166 = c2165 + 1;\nconst c2167 = c2166 + 1;\nconst c2168 = c2167 + 1;\nconst c2169 = c2168 + 1;\nconst c2170 = c2169 + 1;\nconst c2171 = c2170 + 1;\nconst c2172 = c2171 + 1;\nconst c2173 = c2172 + 1;\nconst c2174 = c2173 + 1;\nconst c2175 = c2174 + 1;\nconst c2176 = c2175 + 1;\nconst c2177 = c2176 + 1;\nconst c2178 = c2177 + 1;\nconst c2179 = c2178 + 1;\nconst c2180 = c2179 + 1;\nconst c2181 = c2180 + 1;\nconst c2182 = c2181 + 1;\nconst c2183 = c2182 + 1;\nconst c2184 = c2183 + 1;\nconst c2185 = c2184 + 1;\nconst c2186 = c2185 + 1;\nconst c2187 = c2186 + 1;\nconst c2188 = c2187 + 1;\nconst c2189 = c2188 + 1;\nconst c2190 = c2189 + 1;\nconst c2191 = c2190 + 1;\nconst c2192 = c2191 + 1;\nconst c2193 = c2192 + 1;\nconst c2194 = c2193 + 1;\nconst c2195 = c2194 + 1;\nconst c2196 = c2195 + 1;\nconst c2197 = c2196 + 1;\nconst c2198 = c2197 + 1;\nconst c2199 = c2198 + 1;\nconst c2200 = c2199 + 1;\nconst c2201 = c2200 + 1;\nconst c2202 = c2201 + 1;\nconst c2203 = c2202 + 1;\nconst c2204 = c2203 + 1;\nconst c2205 = c2204 + 1;\nconst c2206 = c2205 + 1;\nconst c2207 = c2206 + 1;\nconst c2208 = c2207 + 1;\nconst c2209 = c2208 + 1;\nconst c2210 = c2209 + 1;\nconst c2211 = c2210 + 1;\nconst c2212 = c2211 + 1;\nconst c2213 = c2212 + 1;\nconst c2214 = c2213 + 1;\nconst c2215 = c2214 + 1;\nconst c2216 = c2215 + 1;\nconst c2217 = c2216 + 1;\nconst c2218 = c2217 + 1;\nconst c2219 = c2218 + 1;\nconst c2220 = c2219 + 1;\nconst c2221 = c2220 + 1;\nconst c2222 = c2221 + 1;\nconst c2223 = c2222 + 1;\nconst c2224 = c2223 + 1;\nconst c2225 = c2224 + 1;\nconst c2226 = c2225 + 1;\nconst c2227 = c2226 + 1;\nconst c2228 = c2227 + 1;\nconst c2229 = c2228 + 1;\nconst c2230 = c2229 + 1;\nconst c2231 = c2230 + 1;\nconst c2232 = c2231 + 1;\nconst c2233 = c2232 + 1;\nconst c2234 = c2233 + 1;\nconst c2235 = c2234 + 1;\nconst c2236 = c2235 + 1;\nconst c2237 = c2236 + 1;\nconst c2238 = c2237 + 1;\nconst c2239 = c2238 + 1;\nconst c2240 = c2239 + 1;\nconst c2241 = c2240 + 1;\nconst c2242 = c2241 + 1;\nconst c2243 = c2242 + 1;\nconst c2244 = c2243 + 1;\nconst c2245 = c2244 + 1;\nconst c2246 = c2245 + 1;\nconst c2247 = c2246 + 1;\nconst c2248 = c2247 + 1;\nconst c2249 = c2248 + 1;\nconst c2250 = c2249 + 1;\nconst c2251 = c2250 + 1;\nconst c2252 = c2251 + 1;\nconst c2253 = c2252 + 1;\nconst c2254 = c2253 + 1;\nconst c2255 = c2254 + 1;\nconst c2256 = c2255 + 1;\nconst c2257 = c2256 + 1;\nconst c2258 = c2257 + 1;\nconst c2259 = c2258 + 1;\nconst c2260 = c2259 + 1;\nconst c2261 = c2260 + 1;\nconst c2262 = c2261 + 1;\nconst c2263 = c2262 + 1;\nconst c2264 = c2263 + 1;\nconst c2265 = c2264 + 1;\nconst c2266 = c2265 + 1;\nconst c2267 = c2266 + 1;\nconst c2268 = c2267 + 1;\nconst c2269 = c2268 + 1;\nconst c2270 = c2269 + 1;\nconst c2271 = c2270 + 1;\nconst c2272 = c2271 + 1;\nconst c2273 = c2272 + 1;\nconst c2274 = c2273 + 1;\nconst c2275 = c2274 + 1;\nconst c2276 = c2275 + 1;\nconst c2277 = c2276 + 1;\nconst c2278 = c2277 + 1;\nconst c2279 = c2278 + 1;\nconst c2280 = c2279 + 1;\nconst c2281 = c2280 + 1;\nconst c2282 = c2281 + 1;\nconst c2283 = c2282 + 1;\nconst c2284 = c2283 + 1;\nconst c2285 = c2284 + 1;\nconst c2286 = c2285 + 1;\nconst c2287 = c2286 + 1;\nconst c2288 = c2287 + 1;\nconst c2289 = c2288 + 1;\nconst c2290 = c2289 + 1;\nconst c2291 = c2290 + 1;\nconst c2292 = c2291 + 1;\nconst c2293 = c2292 + 1;\nconst c2294 = c2293 + 1;\nconst c2295 = c2294 + 1;\nconst c2296 = c2295 + 1;\nconst c2297 = c2296 + 1;\nconst c2298 = c2297 + 1;\nconst c2299 = c2298 + 1;\nconst c2300 = c2299 + 1;\nconst c2301 = c2300 + 1;\nconst c2302 = c2301 + 1;\nconst c2303 = c2302 + 1;\nconst c2304 = c2303 + 1;\nconst c2305 = c2304 + 1;\nconst c2306 = c2305 + 1;\nconst c2307 = c2306 + 1;\nconst c2308 = c2307 + 1;\nconst c2309 = c2308 + 1;\nconst c2310 = c2309 + 1;\nconst c2311 = c2310 + 1;\nconst c2312 = c2311 + 1;\nconst c2313 = c2312 + 1;\nconst c2314 = c2313 + 1;\nconst c2315 = c2314 + 1;\nconst c2316 = c2315 + 1;\nconst c2317 = c2316 + 1;\nconst c2318 = c2317 + 1;\nconst c2319 = c2318 + 1;\nconst c2320 = c2319 + 1;\nconst c2321 = c2320 + 1;\nconst c2322 = c2321 + 1;\nconst c2323 = c2322 + 1;\nconst c2324 = c2323 + 1;\nconst c2325 = c2324 + 1;\nconst c2326 = c2325 + 1;\nconst c2327 = c2326 + 1;\nconst c2328 = c2327 + 1;\nconst c2329 = c2328 + 1;\nconst c2330 = c2329 + 1;\nconst c2331 = c2330 + 1;\nconst c2332 = c2331 + 1;\nconst c2333 = c2332 + 1;\nconst c2334 = c2333 + 1;\nconst c2335 = c2334 + 1;\nconst c2336 = c2335 + 1;\nconst c2337 = c2336 + 1;\nconst c2338 = c2337 + 1;\nconst c2339 = c2338 + 1;\nconst c2340 = c2339 + 1;\nconst c2341 = c2340 + 1;\nconst c2342 = c2341 + 1;\nconst c2343 = c2342 + 1;\nconst c2344 = c2343 + 1;\nconst c2345 = c2344 + 1;\nconst c2346 = c2345 + 1;\nconst c2347 = c2346 + 1;\nconst c2348 = c2347 + 1;\nconst c2349 = c2348 + 1;\nconst c2350 = c2349 + 1;\nconst c2351 = c2350 + 1;\nconst c2352 = c2351 + 1;\nconst c2353 = c2352 + 1;\nconst c2354 = c2353 + 1;\nconst c2355 = c2354 + 1;\nconst c2356 = c2355 + 1;\nconst c2357 = c2356 + 1;\nconst c2358 = c2357 + 1;\nconst c2359 = c2358 + 1;\nconst c2360 = c2359 + 1;\nconst c2361 = c2360 + 1;\nconst c2362 = c2361 + 1;\nconst c2363 = c2362 + 1;\nconst c2364 = c2363 + 1;\nconst c2365 = c2364 + 1;\nconst c2366 = c2365 + 1;\nconst c2367 = c2366 + 1;\nconst c2368 = c2367 + 1;\nconst c2369 = c2368 + 1;\nconst c2370 = c2369 + 1;\nconst c2371 = c2370 + 1;\nconst c2372 = c2371 + 1;\nconst c2373 = c2372 + 1;\nconst c2374 = c2373 + 1;\nconst c2375 = c2374 + 1;\nconst c2376 = c2375 + 1;\nconst c2377 = c2376 + 1;\nconst c2378 = c2377 + 1;\nconst c2379 = c2378 + 1;\nconst c2380 = c2379 + 1;\nconst c2381 = c2380 + 1;\nconst c2382 = c2381 + 1;\nconst c2383 = c2382 + 1;\nconst c2384 = c2383 + 1;\nconst c2385 = c2384 + 1;\nconst c2386 = c2385 + 1;\nconst c2387 = c2386 + 1;\nconst c2388 = c2387 + 1;\nconst c2389 = c2388 + 1;\nconst c2390 = c2389 + 1;\nconst c2391 = c2390 + 1;\nconst c2392 = c2391 + 1;\nconst c2393 = c2392 + 1;\nconst c2394 = c2393 + 1;\nconst c2395 = c2394 + 1;\nconst c2396 = c2395 + 1;\nconst c2397 = c2396 + 1;\nconst c2398 = c2397 + 1;\nconst c2399 = c2398 + 1;\nconst c2400 = c2399 + 1;\nconst c2401 = c2400 + 1;\nconst c2402 = c2401 + 1;\nconst c2403 = c2402 + 1;\nconst c2404 = c2403 + 1;\nconst c2405 = c2404 + 1;\nconst c2406 = c2405 + 1;\nconst c2407 = c2406 + 1;\nconst c2408 = c2407 + 1;\nconst c2409 = c2408 + 1;\nconst c2410 = c2409 + 1;\nconst c2411 = c2410 + 1;\nconst c2412 = c2411 + 1;\nconst c2413 = c2412 + 1;\nconst c2414 = c2413 + 1;\nconst c2415 = c2414 + 1;\nconst c2416 = c2415 + 1;\nconst c2417 = c2416 + 1;\nconst c2418 = c2417 + 1;\nconst c2419 = c2418 + 1;\nconst c2420 = c2419 + 1;\nconst c2421 = c2420 + 1;\nconst c2422 = c2421 + 1;\nconst c2423 = c2422 + 1;\nconst c2424 = c2423 + 1;\nconst c2425 = c2424 + 1;\nconst c2426 = c2425 + 1;\nconst c2427 = c2426 + 1;\nconst c2428 = c2427 + 1;\nconst c2429 = c2428 + 1;\nconst c2430 = c2429 + 1;\nconst c2431 = c2430 + 1;\nconst c2432 = c2431 + 1;\nconst c2433 = c2432 + 1;\nconst c2434 = c2433 + 1;\nconst c2435 = c2434 + 1;\nconst c2436 = c2435 + 1;\nconst c2437 = c2436 + 1;\nconst c2438 = c2437 + 1;\nconst c2439 = c2438 + 1;\nconst c2440 = c2439 + 1;\nconst c2441 = c2440 + 1;\nconst c2442 = c2441 + 1;\nconst c2443 = c2442 + 1;\nconst c2444 = c2443 + 1;\nconst c2445 = c2444 + 1;\nconst c2446 = c2445 + 1;\nconst c2447 = c2446 + 1;\nconst c2448 = c2447 + 1;\nconst c2449 = c2448 + 1;\nconst c2450 = c2449 + 1;\nconst c2451 = c2450 + 1;\nconst c2452 = c2451 + 1;\nconst c2453 = c2452 + 1;\nconst c2454 = c2453 + 1;\nconst c2455 = c2454 + 1;\nconst c2456 = c2455 + 1;\nconst c2457 = c2456 + 1;\nconst c2458 = c2457 + 1;\nconst c2459 = c2458 + 1;\nconst c2460 = c2459 + 1;\nconst c2461 = c2460 + 1;\nconst c2462 = c2461 + 1;\nconst c2463 = c2462 + 1;\nconst c2464 = c2463 + 1;\nconst c2465 = c2464 + 1;\nconst c2466 = c2465 + 1;\nconst c2467 = c2466 + 1;\nconst c2468 = c2467 + 1;\nconst c2469 = c2468 + 1;\nconst c2470 = c2469 + 1;\nconst c2471 = c2470 + 1;\nconst c2472 = c2471 + 1;\nconst c2473 = c2472 + 1;\nconst c2474 = c2473 + 1;\nconst c2475 = c2474 + 1;\nconst c2476 = c2475 + 1;\nconst c2477 = c2476 + 1;\nconst c2478 = c2477 + 1;\nconst c2479 = c2478 + 1;\nconst c2480 = c2479 + 1;\nconst c2481 = c2480 + 1;\nconst c2482 = c2481 + 1;\nconst c2483 = c2482 + 1;\nconst c2484 = c2483 + 1;\nconst c2485 = c2484 + 1;\nconst c2486 = c2485 + 1;\nconst c2487 = c2486 + 1;\nconst c2488 = c2487 + 1;\nconst c2489 = c2488 + 1;\nconst c2490 = c2489 + 1;\nconst c2491 = c2490 + 1;\nconst c2492 = c2491 + 1;\nconst c2493 = c2492 + 1;\nconst c2494 = c2493 + 1;\nconst c2495 = c2494 + 1;\nconst c2496 = c2495 + 1;\nconst c2497 = c2496 + 1;\nconst c2498 = c2497 + 1;\nconst c2499 = c2498 + 1;\nconst c2500 = c2499 + 1;\nconst c2501 = c2500 + 1;\nconst c2502 = c2501 + 1;\nconst c2503 = c2502 + 1;\nconst c2504 = c2503 + 1;\nconst c2505 = c2504 + 1;\nconst c2506 = c2505 + 1;\nconst c2507 = c2506 + 1;\nconst c2508 = c2507 + 1;\nconst c2509 = c2508 + 1;\nconst c2510 = c2509 + 1;\nconst c2511 = c2510 + 1;\nconst c2512 = c2511 + 1;\nconst c2513 = c2512 + 1;\nconst c2514 = c2513 + 1;\nconst c2515 = c2514 + 1;\nconst c2516 = c2515 + 1;\nconst c2517 = c2516 + 1;\nconst c2518 = c2517 + 1;\nconst c2519 = c2518 + 1;\nconst c2520 = c2519 + 1;\nconst c2521 = c2520 + 1;\nconst c2522 = c2521 + 1;\nconst c2523 = c2522 + 1;\nconst c2524 = c2523 + 1;\nconst c2525 = c2524 + 1;\nconst c2526 = c2525 + 1;\nconst c2527 = c2526 + 1;\nconst c2528 = c2527 + 1;\nconst c2529 = c2528 + 1;\nconst c2530 = c2529 + 1;\nconst c2531 = c2530 + 1;\nconst c2532 = c2531 + 1;\nconst c2533 = c2532 + 1;\nconst c2534 = c2533 + 1;\nconst c2535 = c2534 + 1;\nconst c2536 = c2535 + 1;\nconst c2537 = c2536 + 1;\nconst c2538 = c2537 + 1;\nconst c2539 = c2538 + 1;\nconst c2540 = c2539 + 1;\nconst c2541 = c2540 + 1;\nconst c2542 = c2541 + 1;\nconst c2543 = c2542 + 1;\nconst c2544 = c2543 + 1;\nconst c2545 = c2544 + 1;\nconst c2546 = c2545 + 1;\nconst c2547 = c2546 + 1;\nconst c2548 = c2547 + 1;\nconst c2549 = c2548 + 1;\nconst c2550 = c2549 + 1;\nconst c2551 = c2550 + 1;\nconst c2552 = c2551 + 1;\nconst c2553 = c2552 + 1;\nconst c2554 = c2553 + 1;\nconst c2555 = c2554 + 1;\nconst c2556 = c2555 + 1;\nconst c2557 = c2556 + 1;\nconst c2558 = c2557 + 1;\nconst c2559 = c2558 + 1;\nconst c2560 = c2559 + 1;\nconst c2561 = c2560 + 1;\nconst c2562 = c2561 + 1;\nconst c2563 = c2562 + 1;\nconst c2564 = c2563 + 1;\nconst c2565 = c2564 + 1;\nconst c2566 = c2565 + 1;\nconst c2567 = c2566 + 1;\nconst c2568 = c2567 + 1;\nconst c2569 = c2568 + 1;\nconst c2570 = c2569 + 1;\nconst c2571 = c2570 + 1;\nconst c2572 = c2571 + 1;\nconst c2573 = c2572 + 1;\nconst c2574 = c2573 + 1;\nconst c2575 = c2574 + 1;\nconst c2576 = c2575 + 1;\nconst c2577 = c2576 + 1;\nconst c2578 = c2577 + 1;\nconst c2579 = c2578 + 1;\nconst c2580 = c2579 + 1;\nconst c2581 = c2580 + 1;\nconst c2582 = c2581 + 1;\nconst c2583 = c2582 + 1;\nconst c2584 = c2583 + 1;\nconst c2585 = c2584 + 1;\nconst c2586 = c2585 + 1;\nconst c2587 = c2586 + 1;\nconst c2588 = c2587 + 1;\nconst c2589 = c2588 + 1;\nconst c2590 = c2589 + 1;\nconst c2591 = c2590 + 1;\nconst c2592 = c2591 + 1;\nconst c2593 = c2592 + 1;\nconst c2594 = c2593 + 1;\nconst c2595 = c2594 + 1;\nconst c2596 = c2595 + 1;\nconst c2597 = c2596 + 1;\nconst c2598 = c2597 + 1;\nconst c2599 = c2598 + 1;\nconst c2600 = c2599 + 1;\nconst c2601 = c2600 + 1;\nconst c2602 = c2601 + 1;\nconst c2603 = c2602 + 1;\nconst c2604 = c2603 + 1;\nconst c2605 = c2604 + 1;\nconst c2606 = c2605 + 1;\nconst c2607 = c2606 + 1;\nconst c2608 = c2607 + 1;\nconst c2609 = c2608 + 1;\nconst c2610 = c2609 + 1;\nconst c2611 = c2610 + 1;\nconst c2612 = c2611 + 1;\nconst c2613 = c2612 + 1;\nconst c2614 = c2613 + 1;\nconst c2615 = c2614 + 1;\nconst c2616 = c2615 + 1;\nconst c2617 = c2616 + 1;\nconst c2618 = c2617 + 1;\nconst c2619 = c2618 + 1;\nconst c2620 = c2619 + 1;\nconst c2621 = c2620 + 1;\nconst c2622 = c2621 + 1;\nconst c2623 = c2622 + 1;\nconst c2624 = c2623 + 1;\nconst c2625 = c2624 + 1;\nconst c2626 = c2625 + 1;\nconst c2627 = c2626 + 1;\nconst c2628 = c2627 + 1;\nconst c2629 = c2628 + 1;\nconst c2630 = c2629 + 1;\nconst c2631 = c2630 + 1;\nconst c2632 = c2631 + 1;\nconst c2633 = c2632 + 1;\nconst c2634 = c2633 + 1;\nconst c2635 = c2634 + 1;\nconst c2636 = c2635 + 1;\nconst c2637 = c2636 + 1;\nconst c2638 = c2637 + 1;\nconst c2639 = c2638 + 1;\nconst c2640 = c2639 + 1;\nconst c2641 = c2640 + 1;\nconst c2642 = c2641 + 1;\nconst c2643 = c2642 + 1;\nconst c2644 = c2643 + 1;\nconst c2645 = c2644 + 1;\nconst c2646 = c2645 + 1;\nconst c2647 = c2646 + 1;\nconst c2648 = c2647 + 1;\nconst c2649 = c2648 + 1;\nconst c2650 = c2649 + 1;\nconst c2651 = c2650 + 1;\nconst c2652 = c2651 + 1;\nconst c2653 = c2652 + 1;\nconst c2654 = c2653 + 1;\nconst c2655 = c2654 + 1;\nconst c2656 = c2655 + 1;\nconst c2657 = c2656 + 1;\nconst c2658 = c2657 + 1;\nconst c2659 = c2658 + 1;\nconst c2660 = c2659 + 1;\nconst c2661 = c2660 + 1;\nconst c2662 = c2661 + 1;\nconst c2663 = c2662 + 1;\nconst c2664 = c2663 + 1;\nconst c2665 = c2664 + 1;\nconst c2666 = c2665 + 1;\nconst c2667 = c2666 + 1;\nconst c2668 = c2667 + 1;\nconst c2669 = c2668 + 1;\nconst c2670 = c2669 + 1;\nconst c2671 = c2670 + 1;\nconst c2672 = c2671 + 1;\nconst c2673 = c2672 + 1;\nconst c2674 = c2673 + 1;\nconst c2675 = c2674 + 1;\nconst c2676 = c2675 + 1;\nconst c2677 = c2676 + 1;\nconst c2678 = c2677 + 1;\nconst c2679 = c2678 + 1;\nconst c2680 = c2679 + 1;\nconst c2681 = c2680 + 1;\nconst c2682 = c2681 + 1;\nconst c2683 = c2682 + 1;\nconst c2684 = c2683 + 1;\nconst c2685 = c2684 + 1;\nconst c2686 = c2685 + 1;\nconst c2687 = c2686 + 1;\nconst c2688 = c2687 + 1;\nconst c2689 = c2688 + 1;\nconst c2690 = c2689 + 1;\nconst c2691 = c2690 + 1;\nconst c2692 = c2691 + 1;\nconst c2693 = c2692 + 1;\nconst c2694 = c2693 + 1;\nconst c2695 = c2694 + 1;\nconst c2696 = c2695 + 1;\nconst c2697 = c2696 + 1;\nconst c2698 = c2697 + 1;\nconst c2699 = c2698 + 1;\nconst c2700 = c2699 + 1;\nconst c2701 = c2700 + 1;\nconst c2702 = c2701 + 1;\nconst c2703 = c2702 + 1;\nconst c2704 = c2703 + 1;\nconst c2705 = c2704 + 1;\nconst c2706 = c2705 + 1;\nconst c2707 = c2706 + 1;\nconst c2708 = c2707 + 1;\nconst c2709 = c2708 + 1;\nconst c2710 = c2709 + 1;\nconst c2711 = c2710 + 1;\nconst c2712 = c2711 + 1;\nconst c2713 = c2712 + 1;\nconst c2714 = c2713 + 1;\nconst c2715 = c2714 + 1;\nconst c2716 = c2715 + 1;\nconst c2717 = c2716 + 1;\nconst c2718 = c2717 + 1;\nconst c2719 = c2718 + 1;\nconst c2720 = c2719 + 1;\nconst c2721 = c2720 + 1;\nconst c2722 = c2721 + 1;\nconst c2723 = c2722 + 1;\nconst c2724 = c2723 + 1;\nconst c2725 = c2724 + 1;\nconst c2726 = c2725 + 1;\nconst c2727 = c2726 + 1;\nconst c2728 = c2727 + 1;\nconst c2729 = c2728 + 1;\nconst c2730 = c2729 + 1;\nconst c2731 = c2730 + 1;\nconst c2732 = c2731 + 1;\nconst c2733 = c2732 + 1;\nconst c2734 = c2733 + 1;\nconst c2735 = c2734 + 1;\nconst c2736 = c2735 + 1;\nconst c2737 = c2736 + 1;\nconst c2738 = c2737 + 1;\nconst c2739 = c2738 + 1;\nconst c2740 = c2739 + 1;\nconst c2741 = c2740 + 1;\nconst c2742 = c2741 + 1;\nconst c2743 = c2742 + 1;\nconst c2744 = c2743 + 1;\nconst c2745 = c2744 + 1;\nconst c2746 = c2745 + 1;\nconst c2747 = c2746 + 1;\nconst c2748 = c2747 + 1;\nconst c2749 = c2748 + 1;\nconst c2750 = c2749 + 1;\nconst c2751 = c2750 + 1;\nconst c2752 = c2751 + 1;\nconst c2753 = c2752 + 1;\nconst c2754 = c2753 + 1;\nconst c2755 = c2754 + 1;\nconst c2756 = c2755 + 1;\nconst c2757 = c2756 + 1;\nconst c2758 = c2757 + 1;\nconst c2759 = c2758 + 1;\nconst c2760 = c2759 + 1;\nconst c2761 = c2760 + 1;\nconst c2762 = c2761 + 1;\nconst c2763 = c2762 + 1;\nconst c2764 = c2763 + 1;\nconst c2765 = c2764 + 1;\nconst c2766 = c2765 + 1;\nconst c2767 = c2766 + 1;\nconst c2768 = c2767 + 1;\nconst c2769 = c2768 + 1;\nconst c2770 = c2769 + 1;\nconst c2771 = c2770 + 1;\nconst c2772 = c2771 + 1;\nconst c2773 = c2772 + 1;\nconst c2774 = c2773 + 1;\nconst c2775 = c2774 + 1;\nconst c2776 = c2775 + 1;\nconst c2777 = c2776 + 1;\nconst c2778 = c2777 + 1;\nconst c2779 = c2778 + 1;\nconst c2780 = c2779 + 1;\nconst c2781 = c2780 + 1;\nconst c2782 = c2781 + 1;\nconst c2783 = c2782 + 1;\nconst c2784 = c2783 + 1;\nconst c2785 = c2784 + 1;\nconst c2786 = c2785 + 1;\nconst c2787 = c2786 + 1;\nconst c2788 = c2787 + 1;\nconst c2789 = c2788 + 1;\nconst c2790 = c2789 + 1;\nconst c2791 = c2790 + 1;\nconst c2792 = c2791 + 1;\nconst c2793 = c2792 + 1;\nconst c2794 = c2793 + 1;\nconst c2795 = c2794 + 1;\nconst c2796 = c2795 + 1;\nconst c2797 = c2796 + 1;\nconst c2798 = c2797 + 1;\nconst c2799 = c2798 + 1;\nconst c2800 = c2799 + 1;\nconst c2801 = c2800 + 1;\nconst c2802 = c2801 + 1;\nconst c2803 = c2802 + 1;\nconst c2804 = c2803 + 1;\nconst c2805 = c2804 + 1;\nconst c2806 = c2805 + 1;\nconst c2807 = c2806 + 1;\nconst c2808 = c2807 + 1;\nconst c2809 = c2808 + 1;\nconst c2810 = c2809 + 1;\nconst c2811 = c2810 + 1;\nconst c2812 = c2811 + 1;\nconst c2813 = c2812 + 1;\nconst c2814 = c2813 + 1;\nconst c2815 = c2814 + 1;\nconst c2816 = c2815 + 1;\nconst c2817 = c2816 + 1;\nconst c2818 = c2817 + 1;\nconst c2819 = c2818 + 1;\nconst c2820 = c2819 + 1;\nconst c2821 = c2820 + 1;\nconst c2822 = c2821 + 1;\nconst c2823 = c2822 + 1;\nconst c2824 = c2823 + 1;\nconst c2825 = c2824 + 1;\nconst c2826 = c2825 + 1;\nconst c2827 = c2826 + 1;\nconst c2828 = c2827 + 1;\nconst c2829 = c2828 + 1;\nconst c2830 = c2829 + 1;\nconst c2831 = c2830 + 1;\nconst c2832 = c2831 + 1;\nconst c2833 = c2832 + 1;\nconst c2834 = c2833 + 1;\nconst c2835 = c2834 + 1;\nconst c2836 = c2835 + 1;\nconst c2837 = c2836 + 1;\nconst c2838 = c2837 + 1;\nconst c2839 = c2838 + 1;\nconst c2840 = c2839 + 1;\nconst c2841 = c2840 + 1;\nconst c2842 = c2841 + 1;\nconst c2843 = c2842 + 1;\nconst c2844 = c2843 + 1;\nconst c2845 = c2844 + 1;\nconst c2846 = c2845 + 1;\nconst c2847 = c2846 + 1;\nconst c2848 = c2847 + 1;\nconst c2849 = c2848 + 1;\nconst c2850 = c2849 + 1;\nconst c2851 = c2850 + 1;\nconst c2852 = c2851 + 1;\nconst c2853 = c2852 + 1;\nconst c2854 = c2853 + 1;\nconst c2855 = c2854 + 1;\nconst c2856 = c2855 + 1;\nconst c2857 = c2856 + 1;\nconst c2858 = c2857 + 1;\nconst c2859 = c2858 + 1;\nconst c2860 = c2859 + 1;\nconst c2861 = c2860 + 1;\nconst c2862 = c2861 + 1;\nconst c2863 = c2862 + 1;\nconst c2864 = c2863 + 1;\nconst c2865 = c2864 + 1;\nconst c2866 = c2865 + 1;\nconst c2867 = c2866 + 1;\nconst c2868 = c2867 + 1;\nconst c2869 = c2868 + 1;\nconst c2870 = c2869 + 1;\nconst c2871 = c2870 + 1;\nconst c2872 = c2871 + 1;\nconst c2873 = c2872 + 1;\nconst c2874 = c2873 + 1;\nconst c2875 = c2874 + 1;\nconst c2876 = c2875 + 1;\nconst c2877 = c2876 + 1;\nconst c2878 = c2877 + 1;\nconst c2879 = c2878 + 1;\nconst c2880 = c2879 + 1;\nconst c2881 = c2880 + 1;\nconst c2882 = c2881 + 1;\nconst c2883 = c2882 + 1;\nconst c2884 = c2883 + 1;\nconst c2885 = c2884 + 1;\nconst c2886 = c2885 + 1;\nconst c2887 = c2886 + 1;\nconst c2888 = c2887 + 1;\nconst c2889 = c2888 + 1;\nconst c2890 = c2889 + 1;\nconst c2891 = c2890 + 1;\nconst c2892 = c2891 + 1;\nconst c2893 = c2892 + 1;\nconst c2894 = c2893 + 1;\nconst c2895 = c2894 + 1;\nconst c2896 = c2895 + 1;\nconst c2897 = c2896 + 1;\nconst c2898 = c2897 + 1;\nconst c2899 = c2898 + 1;\nconst c2900 = c2899 + 1;\nconst c2901 = c2900 + 1;\nconst c2902 = c2901 + 1;\nconst c2903 = c2902 + 1;\nconst c2904 = c2903 + 1;\nconst c2905 = c2904 + 1;\nconst c2906 = c2905 + 1;\nconst c2907 = c2906 + 1;\nconst c2908 = c2907 + 1;\nconst c2909 = c2908 + 1;\nconst c2910 = c2909 + 1;\nconst c2911 = c2910 + 1;\nconst c2912 = c2911 + 1;\nconst c2913 = c2912 + 1;\nconst c2914 = c2913 + 1;\nconst c2915 = c2914 + 1;\nconst c2916 = c2915 + 1;\nconst c2917 = c2916 + 1;\nconst c2918 = c2917 + 1;\nconst c2919 = c2918 + 1;\nconst c2920 = c2919 + 1;\nconst c2921 = c2920 + 1;\nconst c2922 = c2921 + 1;\nconst c2923 = c2922 + 1;\nconst c2924 = c2923 + 1;\nconst c2925 = c2924 + 1;\nconst c2926 = c2925 + 1;\nconst c2927 = c2926 + 1;\nconst c2928 = c2927 + 1;\nconst c2929 = c2928 + 1;\nconst c2930 = c2929 + 1;\nconst c2931 = c2930 + 1;\nconst c2932 = c2931 + 1;\nconst c2933 = c2932 + 1;\nconst c2934 = c2933 + 1;\nconst c2935 = c2934 + 1;\nconst c2936 = c2935 + 1;\nconst c2937 = c2936 + 1;\nconst c2938 = c2937 + 1;\nconst c2939 = c2938 + 1;\nconst c2940 = c2939 + 1;\nconst c2941 = c2940 + 1;\nconst c2942 = c2941 + 1;\nconst c2943 = c2942 + 1;\nconst c2944 = c2943 + 1;\nconst c2945 = c2944 + 1;\nconst c2946 = c2945 + 1;\nconst c2947 = c2946 + 1;\nconst c2948 = c2947 + 1;\nconst c2949 = c2948 + 1;\nconst c2950 = c2949 + 1;\nconst c2951 = c2950 + 1;\nconst c2952 = c2951 + 1;\nconst c2953 = c2952 + 1;\nconst c2954 = c2953 + 1;\nconst c2955 = c2954 + 1;\nconst c2956 = c2955 + 1;\nconst c2957 = c2956 + 1;\nconst c2958 = c2957 + 1;\nconst c2959 = c2958 + 1;\nconst c2960 = c2959 + 1;\nconst c2961 = c2960 + 1;\nconst c2962 = c2961 + 1;\nconst c2963 = c2962 + 1;\nconst c2964 = c2963 + 1;\nconst c2965 = c2964 + 1;\nconst c2966 = c2965 + 1;\nconst c2967 = c2966 + 1;\nconst c2968 = c2967 + 1;\nconst c2969 = c2968 + 1;\nconst c2970 = c2969 + 1;\nconst c2971 = c2970 + 1;\nconst c2972 = c2971 + 1;\nconst c2973 = c2972 + 1;\nconst c2974 = c2973 + 1;\nconst c2975 = c2974 + 1;\nconst c2976 = c2975 + 1;\nconst c2977 = c2976 + 1;\nconst c2978 = c2977 + 1;\nconst c2979 = c2978 + 1;\nconst c2980 = c2979 + 1;\nconst c2981 = c2980 + 1;\nconst c2982 = c2981 + 1;\nconst c2983 = c2982 + 1;\nconst c2984 = c2983 + 1;\nconst c2985 = c2984 + 1;\nconst c2986 = c2985 + 1;\nconst c2987 = c2986 + 1;\nconst c2988 = c2987 + 1;\nconst c2989 = c2988 + 1;\nconst c2990 = c2989 + 1;\nconst c2991 = c2990 + 1;\nconst c2992 = c2991 + 1;\nconst c2993 = c2992 + 1;\nconst c2994 = c2993 + 1;\nconst c2995 = c2994 + 1;\nconst c2996 = c2995 + 1;\nconst c2997 = c2996 + 1;\nconst c2998 = c2997 + 1;\nconst c2999 = c2998 + 1;\nconst c3000 = c2999 + 1;\nconst c3001 = c3000 + 1;\nconst c3002 = c3001 + 1;\nconst c3003 = c3002 + 1;\nconst c3004 = c3003 + 1;\nconst c3005 = c3004 + 1;\nconst c3006 = c3005 + 1;\nconst c3007 = c3006 + 1;\nconst c3008 = c3007 + 1;\nconst c3009 = c3008 + 1;\nconst c3010 = c3009 + 1;\nconst c3011 = c3010 + 1;\nconst c3012 = c3011 + 1;\nconst c3013 = c3012 + 1;\nconst c3014 = c3013 + 1;\nconst c3015 = c3014 + 1;\nconst c3016 = c3015 + 1;\nconst c3017 = c3016 + 1;\nconst c3018 = c3017 + 1;\nconst c3019 = c3018 + 1;\nconst c3020 = c3019 + 1;\nconst c3021 = c3020 + 1;\nconst c3022 = c3021 + 1;\nconst c3023 = c3022 + 1;\nconst c3024 = c3023 + 1;\nconst c3025 = c3024 + 1;\nconst c3026 = c3025 + 1;\nconst c3027 = c3026 + 1;\nconst c3028 = c3027 + 1;\nconst c3029 = c3028 + 1;\nconst c3030 = c3029 + 1;\nconst c3031 = c3030 + 1;\nconst c3032 = c3031 + 1;\nconst c3033 = c3032 + 1;\nconst c3034 = c3033 + 1;\nconst c3035 = c3034 + 1;\nconst c3036 = c3035 + 1;\nconst c3037 = c3036 + 1;\nconst c3038 = c3037 + 1;\nconst c3039 = c3038 + 1;\nconst c3040 = c3039 + 1;\nconst c3041 = c3040 + 1;\nconst c3042 = c3041 + 1;\nconst c3043 = c3042 + 1;\nconst c3044 = c3043 + 1;\nconst c3045 = c3044 + 1;\nconst c3046 = c3045 + 1;\nconst c3047 = c3046 + 1;\nconst c3048 = c3047 + 1;\nconst c3049 = c3048 + 1;\nconst c3050 = c3049 + 1;\nconst c3051 = c3050 + 1;\nconst c3052 = c3051 + 1;\nconst c3053 = c3052 + 1;\nconst c3054 = c3053 + 1;\nconst c3055 = c3054 + 1;\nconst c3056 = c3055 + 1;\nconst c3057 = c3056 + 1;\nconst c3058 = c3057 + 1;\nconst c3059 = c3058 + 1;\nconst c3060 = c3059 + 1;\nconst c3061 = c3060 + 1;\nconst c3062 = c3061 + 1;\nconst c3063 = c3062 + 1;\nconst c3064 = c3063 + 1;\nconst c3065 = c3064 + 1;\nconst c3066 = c3065 + 1;\nconst c3067 = c3066 + 1;\nconst c3068 = c3067 + 1;\nconst c3069 = c3068 + 1;\nconst c3070 = c3069 + 1;\nconst c3071 = c3070 + 1;\nconst c3072 = c3071 + 1;\nconst c3073 = c3072 + 1;\nconst c3074 = c3073 + 1;\nconst c3075 = c3074 + 1;\nconst c3076 = c3075 + 1;\nconst c3077 = c3076 + 1;\nconst c3078 = c3077 + 1;\nconst c3079 = c3078 + 1;\nconst c3080 = c3079 + 1;\nconst c3081 = c3080 + 1;\nconst c3082 = c3081 + 1;\nconst c3083 = c3082 + 1;\nconst c3084 = c3083 + 1;\nconst c3085 = c3084 + 1;\nconst c3086 = c3085 + 1;\nconst c3087 = c3086 + 1;\nconst c3088 = c3087 + 1;\nconst c3089 = c3088 + 1;\nconst c3090 = c3089 + 1;\nconst c3091 = c3090 + 1;\nconst c3092 = c3091 + 1;\nconst c3093 = c3092 + 1;\nconst c3094 = c3093 + 1;\nconst c3095 = c3094 + 1;\nconst c3096 = c3095 + 1;\nconst c3097 = c3096 + 1;\nconst c3098 = c3097 + 1;\nconst c3099 = c3098 + 1;\nconst c3100 = c3099 + 1;\nconst c3101 = c3100 + 1;\nconst c3102 = c3101 + 1;\nconst c3103 = c3102 + 1;\nconst c3104 = c3103 + 1;\nconst c3105 = c3104 + 1;\nconst c3106 = c3105 + 1;\nconst c3107 = c3106 + 1;\nconst c3108 = c3107 + 1;\nconst c3109 = c3108 + 1;\nconst c3110 = c3109 + 1;\nconst c3111 = c3110 + 1;\nconst c3112 = c3111 + 1;\nconst c3113 = c3112 + 1;\nconst c3114 = c3113 + 1;\nconst c3115 = c3114 + 1;\nconst c3116 = c3115 + 1;\nconst c3117 = c3116 + 1;\nconst c3118 = c3117 + 1;\nconst c3119 = c3118 + 1;\nconst c3120 = c3119 + 1;\nconst c3121 = c3120 + 1;\nconst c3122 = c3121 + 1;\nconst c3123 = c3122 + 1;\nconst c3124 = c3123 + 1;\nconst c3125 = c3124 + 1;\nconst c3126 = c3125 + 1;\nconst c3127 = c3126 + 1;\nconst c3128 = c3127 + 1;\nconst c3129 = c3128 + 1;\nconst c3130 = c3129 + 1;\nconst c3131 = c3130 + 1;\nconst c3132 = c3131 + 1;\nconst c3133 = c3132 + 1;\nconst c3134 = c3133 + 1;\nconst c3135 = c3134 + 1;\nconst c3136 = c3135 + 1;\nconst c3137 = c3136 + 1;\nconst c3138 = c3137 + 1;\nconst c3139 = c3138 + 1;\nconst c3140 = c3139 + 1;\nconst c3141 = c3140 + 1;\nconst c3142 = c3141 + 1;\nconst c3143 = c3142 + 1;\nconst c3144 = c3143 + 1;\nconst c3145 = c3144 + 1;\nconst c3146 = c3145 + 1;\nconst c3147 = c3146 + 1;\nconst c3148 = c3147 + 1;\nconst c3149 = c3148 + 1;\nconst c3150 = c3149 + 1;\nconst c3151 = c3150 + 1;\nconst c3152 = c3151 + 1;\nconst c3153 = c3152 + 1;\nconst c3154 = c3153 + 1;\nconst c3155 = c3154 + 1;\nconst c3156 = c3155 + 1;\nconst c3157 = c3156 + 1;\nconst c3158 = c3157 + 1;\nconst c3159 = c3158 + 1;\nconst c3160 = c3159 + 1;\nconst c3161 = c3160 + 1;\nconst c3162 = c3161 + 1;\nconst c3163 = c3162 + 1;\nconst c3164 = c3163 + 1;\nconst c3165 = c3164 + 1;\nconst c3166 = c3165 + 1;\nconst c3167 = c3166 + 1;\nconst c3168 = c3167 + 1;\nconst c3169 = c3168 + 1;\nconst c3170 = c3169 + 1;\nconst c3171 = c3170 + 1;\nconst c3172 = c3171 + 1;\nconst c3173 = c3172 + 1;\nconst c3174 = c3173 + 1;\nconst c3175 = c3174 + 1;\nconst c3176 = c3175 + 1;\nconst c3177 = c3176 + 1;\nconst c3178 = c3177 + 1;\nconst c3179 = c3178 + 1;\nconst c3180 = c3179 + 1;\nconst c3181 = c3180 + 1;\nconst c3182 = c3181 + 1;\nconst c3183 = c3182 + 1;\nconst c3184 = c3183 + 1;\nconst c3185 = c3184 + 1;\nconst c3186 = c3185 + 1;\nconst c3187 = c3186 + 1;\nconst c3188 = c3187 + 1;\nconst c3189 = c3188 + 1;\nconst c3190 = c3189 + 1;\nconst c3191 = c3190 + 1;\nconst c3192 = c3191 + 1;\nconst c3193 = c3192 + 1;\nconst c3194 = c3193 + 1;\nconst c3195 = c3194 + 1;\nconst c3196 = c3195 + 1;\nconst c3197 = c3196 + 1;\nconst c3198 = c3197 + 1;\nconst c3199 = c3198 + 1;\nconst c3200 = c3199 + 1;\nconst c3201 = c3200 + 1;\nconst c3202 = c3201 + 1;\nconst c3203 = c3202 + 1;\nconst c3204 = c3203 + 1;\nconst c3205 = c3204 + 1;\nconst c3206 = c3205 + 1;\nconst c3207 = c3206 + 1;\nconst c3208 = c3207 + 1;\nconst c3209 = c3208 + 1;\nconst c3210 = c3209 + 1;\nconst c3211 = c3210 + 1;\nconst c3212 = c3211 + 1;\nconst c3213 = c3212 + 1;\nconst c3214 = c3213 + 1;\nconst c3215 = c3214 + 1;\nconst c3216 = c3215 + 1;\nconst c3217 = c3216 + 1;\nconst c3218 = c3217 + 1;\nconst c3219 = c3218 + 1;\nconst c3220 = c3219 + 1;\nconst c3221 = c3220 + 1;\nconst c3222 = c3221 + 1;\nconst c3223 = c3222 + 1;\nconst c3224 = c3223 + 1;\nconst c3225 = c3224 + 1;\nconst c3226 = c3225 + 1;\nconst c3227 = c3226 + 1;\nconst c3228 = c3227 + 1;\nconst c3229 = c3228 + 1;\nconst c3230 = c3229 + 1;\nconst c3231 = c3230 + 1;\nconst c3232 = c3231 + 1;\nconst c3233 = c3232 + 1;\nconst c3234 = c3233 + 1;\nconst c3235 = c3234 + 1;\nconst c3236 = c3235 + 1;\nconst c3237 = c3236 + 1;\nconst c3238 = c3237 + 1;\nconst c3239 = c3238 + 1;\nconst c3240 = c3239 + 1;\nconst c3241 = c3240 + 1;\nconst c3242 = c3241 + 1;\nconst c3243 = c3242 + 1;\nconst c3244 = c3243 + 1;\nconst c3245 = c3244 + 1;\nconst c3246 = c3245 + 1;\nconst c3247 = c3246 + 1;\nconst c3248 = c3247 + 1;\nconst c3249 = c3248 + 1;\nconst c3250 = c3249 + 1;\nconst c3251 = c3250 + 1;\nconst c3252 = c3251 + 1;\nconst c3253 = c3252 + 1;\nconst c3254 = c3253 + 1;\nconst c3255 = c3254 + 1;\nconst c3256 = c3255 + 1;\nconst c3257 = c3256 + 1;\nconst c3258 = c3257 + 1;\nconst c3259 = c3258 + 1;\nconst c3260 = c3259 + 1;\nconst c3261 = c3260 + 1;\nconst c3262 = c3261 + 1;\nconst c3263 = c3262 + 1;\nconst c3264 = c3263 + 1;\nconst c3265 = c3264 + 1;\nconst c3266 = c3265 + 1;\nconst c3267 = c3266 + 1;\nconst c3268 = c3267 + 1;\nconst c3269 = c3268 + 1;\nconst c3270 = c3269 + 1;\nconst c3271 = c3270 + 1;\nconst c3272 = c3271 + 1;\nconst c3273 = c3272 + 1;\nconst c3274 = c3273 + 1;\nconst c3275 = c3274 + 1;\nconst c3276 = c3275 + 1;\nconst c3277 = c3276 + 1;\nconst c3278 = c3277 + 1;\nconst c3279 = c3278 + 1;\nconst c3280 = c3279 + 1;\nconst c3281 = c3280 + 1;\nconst c3282 = c3281 + 1;\nconst c3283 = c3282 + 1;\nconst c3284 = c3283 + 1;\nconst c3285 = c3284 + 1;\nconst c3286 = c3285 + 1;\nconst c3287 = c3286 + 1;\nconst c3288 = c3287 + 1;\nconst c3289 = c3288 + 1;\nconst c3290 = c3289 + 1;\nconst c3291 = c3290 + 1;\nconst c3292 = c3291 + 1;\nconst c3293 = c3292 + 1;\nconst c3294 = c3293 + 1;\nconst c3295 = c3294 + 1;\nconst c3296 = c3295 + 1;\nconst c3297 = c3296 + 1;\nconst c3298 = c3297 + 1;\nconst c3299 = c3298 + 1;\nconst c3300 = c3299 + 1;\nconst c3301 = c3300 + 1;\nconst c3302 = c3301 + 1;\nconst c3303 = c3302 + 1;\nconst c3304 = c3303 + 1;\nconst c3305 = c3304 + 1;\nconst c3306 = c3305 + 1;\nconst c3307 = c3306 + 1;\nconst c3308 = c3307 + 1;\nconst c3309 = c3308 + 1;\nconst c3310 = c3309 + 1;\nconst c3311 = c3310 + 1;\nconst c3312 = c3311 + 1;\nconst c3313 = c3312 + 1;\nconst c3314 = c3313 + 1;\nconst c3315 = c3314 + 1;\nconst c3316 = c3315 + 1;\nconst c3317 = c3316 + 1;\nconst c3318 = c3317 + 1;\nconst c3319 = c3318 + 1;\nconst c3320 = c3319 + 1;\nconst c3321 = c3320 + 1;\nconst c3322 = c3321 + 1;\nconst c3323 = c3322 + 1;\nconst c3324 = c3323 + 1;\nconst c3325 = c3324 + 1;\nconst c3326 = c3325 + 1;\nconst c3327 = c3326 + 1;\nconst c3328 = c3327 + 1;\nconst c3329 = c3328 + 1;\nconst c3330 = c3329 + 1;\nconst c3331 = c3330 + 1;\nconst c3332 = c3331 + 1;\nconst c3333 = c3332 + 1;\nconst c3334 = c3333 + 1;\nconst c3335 = c3334 + 1;\nconst c3336 = c3335 + 1;\nconst c3337 = c3336 + 1;\nconst c3338 = c3337 + 1;\nconst c3339 = c3338 + 1;\nconst c3340 = c3339 + 1;\nconst c3341 = c3340 + 1;\nconst c3342 = c3341 + 1;\nconst c3343 = c3342 + 1;\nconst c3344 = c3343 + 1;\nconst c3345 = c3344 + 1;\nconst c3346 = c3345 + 1;\nconst c3347 = c3346 + 1;\nconst c3348 = c3347 + 1;\nconst c3349 = c3348 + 1;\nconst c3350 = c3349 + 1;\nconst c3351 = c3350 + 1;\nconst c3352 = c3351 + 1;\nconst c3353 = c3352 + 1;\nconst c3354 = c3353 + 1;\nconst c3355 = c3354 + 1;\nconst c3356 = c3355 + 1;\nconst c3357 = c3356 + 1;\nconst c3358 = c3357 + 1;\nconst c3359 = c3358 + 1;\nconst c3360 = c3359 + 1;\nconst c3361 = c3360 + 1;\nconst c3362 = c3361 + 1;\nconst c3363 = c3362 + 1;\nconst c3364 = c3363 + 1;\nconst c3365 = c3364 + 1;\nconst c3366 = c3365 + 1;\nconst c3367 = c3366 + 1;\nconst c3368 = c3367 + 1;\nconst c3369 = c3368 + 1;\nconst c3370 = c3369 + 1;\nconst c3371 = c3370 + 1;\nconst c3372 = c3371 + 1;\nconst c3373 = c3372 + 1;\nconst c3374 = c3373 + 1;\nconst c3375 = c3374 + 1;\nconst c3376 = c3375 + 1;\nconst c3377 = c3376 + 1;\nconst c3378 = c3377 + 1;\nconst c3379 = c3378 + 1;\nconst c3380 = c3379 + 1;\nconst c3381 = c3380 + 1;\nconst c3382 = c3381 + 1;\nconst c3383 = c3382 + 1;\nconst c3384 = c3383 + 1;\nconst c3385 = c3384 + 1;\nconst c3386 = c3385 + 1;\nconst c3387 = c3386 + 1;\nconst c3388 = c3387 + 1;\nconst c3389 = c3388 + 1;\nconst c3390 = c3389 + 1;\nconst c3391 = c3390 + 1;\nconst c3392 = c3391 + 1;\nconst c3393 = c3392 + 1;\nconst c3394 = c3393 + 1;\nconst c3395 = c3394 + 1;\nconst c3396 = c3395 + 1;\nconst c3397 = c3396 + 1;\nconst c3398 = c3397 + 1;\nconst c3399 = c3398 + 1;\nconst c3400 = c3399 + 1;\nconst c3401 = c3400 + 1;\nconst c3402 = c3401 + 1;\nconst c3403 = c3402 + 1;\nconst c3404 = c3403 + 1;\nconst c3405 = c3404 + 1;\nconst c3406 = c3405 + 1;\nconst c3407 = c3406 + 1;\nconst c3408 = c3407 + 1;\nconst c3409 = c3408 + 1;\nconst c3410 = c3409 + 1;\nconst c3411 = c3410 + 1;\nconst c3412 = c3411 + 1;\nconst c3413 = c3412 + 1;\nconst c3414 = c3413 + 1;\nconst c3415 = c3414 + 1;\nconst c3416 = c3415 + 1;\nconst c3417 = c3416 + 1;\nconst c3418 = c3417 + 1;\nconst c3419 = c3418 + 1;\nconst c3420 = c3419 + 1;\nconst c3421 = c3420 + 1;\nconst c3422 = c3421 + 1;\nconst c3423 = c3422 + 1;\nconst c3424 = c3423 + 1;\nconst c3425 = c3424 + 1;\nconst c3426 = c3425 + 1;\nconst c3427 = c3426 + 1;\nconst c3428 = c3427 + 1;\nconst c3429 = c3428 + 1;\nconst c3430 = c3429 + 1;\nconst c3431 = c3430 + 1;\nconst c3432 = c3431 + 1;\nconst c3433 = c3432 + 1;\nconst c3434 = c3433 + 1;\nconst c3435 = c3434 + 1;\nconst c3436 = c3435 + 1;\nconst c3437 = c3436 + 1;\nconst c3438 = c3437 + 1;\nconst c3439 = c3438 + 1;\nconst c3440 = c3439 + 1;\nconst c3441 = c3440 + 1;\nconst c3442 = c3441 + 1;\nconst c3443 = c3442 + 1;\nconst c3444 = c3443 + 1;\nconst c3445 = c3444 + 1;\nconst c3446 = c3445 + 1;\nconst c3447 = c3446 + 1;\nconst c3448 = c3447 + 1;\nconst c3449 = c3448 + 1;\nconst c3450 = c3449 + 1;\nconst c3451 = c3450 + 1;\nconst c3452 = c3451 + 1;\nconst c3453 = c3452 + 1;\nconst c3454 = c3453 + 1;\nconst c3455 = c3454 + 1;\nconst c3456 = c3455 + 1;\nconst c3457 = c3456 + 1;\nconst c3458 = c3457 + 1;\nconst c3459 = c3458 + 1;\nconst c3460 = c3459 + 1;\nconst c3461 = c3460 + 1;\nconst c3462 = c3461 + 1;\nconst c3463 = c3462 + 1;\nconst c3464 = c3463 + 1;\nconst c3465 = c3464 + 1;\nconst c3466 = c3465 + 1;\nconst c3467 = c3466 + 1;\nconst c3468 = c3467 + 1;\nconst c3469 = c3468 + 1;\nconst c3470 = c3469 + 1;\nconst c3471 = c3470 + 1;\nconst c3472 = c3471 + 1;\nconst c3473 = c3472 + 1;\nconst c3474 = c3473 + 1;\nconst c3475 = c3474 + 1;\nconst c3476 = c3475 + 1;\nconst c3477 = c3476 + 1;\nconst c3478 = c3477 + 1;\nconst c3479 = c3478 + 1;\nconst c3480 = c3479 + 1;\nconst c3481 = c3480 + 1;\nconst c3482 = c3481 + 1;\nconst c3483 = c3482 + 1;\nconst c3484 = c3483 + 1;\nconst c3485 = c3484 + 1;\nconst c3486 = c3485 + 1;\nconst c3487 = c3486 + 1;\nconst c3488 = c3487 + 1;\nconst c3489 = c3488 + 1;\nconst c3490 = c3489 + 1;\nconst c3491 = c3490 + 1;\nconst c3492 = c3491 + 1;\nconst c3493 = c3492 + 1;\nconst c3494 = c3493 + 1;\nconst c3495 = c3494 + 1;\nconst c3496 = c3495 + 1;\nconst c3497 = c3496 + 1;\nconst c3498 = c3497 + 1;\nconst c3499 = c3498 + 1;\nconst c3500 = c3499 + 1;\nconst c3501 = c3500 + 1;\nconst c3502 = c3501 + 1;\nconst c3503 = c3502 + 1;\nconst c3504 = c3503 + 1;\nconst c3505 = c3504 + 1;\nconst c3506 = c3505 + 1;\nconst c3507 = c3506 + 1;\nconst c3508 = c3507 + 1;\nconst c3509 = c3508 + 1;\nconst c3510 = c3509 + 1;\nconst c3511 = c3510 + 1;\nconst c3512 = c3511 + 1;\nconst c3513 = c3512 + 1;\nconst c3514 = c3513 + 1;\nconst c3515 = c3514 + 1;\nconst c3516 = c3515 + 1;\nconst c3517 = c3516 + 1;\nconst c3518 = c3517 + 1;\nconst c3519 = c3518 + 1;\nconst c3520 = c3519 + 1;\nconst c3521 = c3520 + 1;\nconst c3522 = c3521 + 1;\nconst c3523 = c3522 + 1;\nconst c3524 = c3523 + 1;\nconst c3525 = c3524 + 1;\nconst c3526 = c3525 + 1;\nconst c3527 = c3526 + 1;\nconst c3528 = c3527 + 1;\nconst c3529 = c3528 + 1;\nconst c3530 = c3529 + 1;\nconst c3531 = c3530 + 1;\nconst c3532 = c3531 + 1;\nconst c3533 = c3532 + 1;\nconst c3534 = c3533 + 1;\nconst c3535 = c3534 + 1;\nconst c3536 = c3535 + 1;\nconst c3537 = c3536 + 1;\nconst c3538 = c3537 + 1;\nconst c3539 = c3538 + 1;\nconst c3540 = c3539 + 1;\nconst c3541 = c3540 + 1;\nconst c3542 = c3541 + 1;\nconst c3543 = c3542 + 1;\nconst c3544 = c3543 + 1;\nconst c3545 = c3544 + 1;\nconst c3546 = c3545 + 1;\nconst c3547 = c3546 + 1;\nconst c3548 = c3547 + 1;\nconst c3549 = c3548 + 1;\nconst c3550 = c3549 + 1;\nconst c3551 = c3550 + 1;\nconst c3552 = c3551 + 1;\nconst c3553 = c3552 + 1;\nconst c3554 = c3553 + 1;\nconst c3555 = c3554 + 1;\nconst c3556 = c3555 + 1;\nconst c3557 = c3556 + 1;\nconst c3558 = c3557 + 1;\nconst c3559 = c3558 + 1;\nconst c3560 = c3559 + 1;\nconst c3561 = c3560 + 1;\nconst c3562 = c3561 + 1;\nconst c3563 = c3562 + 1;\nconst c3564 = c3563 + 1;\nconst c3565 = c3564 + 1;\nconst c3566 = c3565 + 1;\nconst c3567 = c3566 + 1;\nconst c3568 = c3567 + 1;\nconst c3569 = c3568 + 1;\nconst c3570 = c3569 + 1;\nconst c3571 = c3570 + 1;\nconst c3572 = c3571 + 1;\nconst c3573 = c3572 + 1;\nconst c3574 = c3573 + 1;\nconst c3575 = c3574 + 1;\nconst c3576 = c3575 + 1;\nconst c3577 = c3576 + 1;\nconst c3578 = c3577 + 1;\nconst c3579 = c3578 + 1;\nconst c3580 = c3579 + 1;\nconst c3581 = c3580 + 1;\nconst c3582 = c3581 + 1;\nconst c3583 = c3582 + 1;\nconst c3584 = c3583 + 1;\nconst c3585 = c3584 + 1;\nconst c3586 = c3585 + 1;\nconst c3587 = c3586 + 1;\nconst c3588 = c3587 + 1;\nconst c3589 = c3588 + 1;\nconst c3590 = c3589 + 1;\nconst c3591 = c3590 + 1;\nconst c3592 = c3591 + 1;\nconst c3593 = c3592 + 1;\nconst c3594 = c3593 + 1;\nconst c3595 = c3594 + 1;\nconst c3596 = c3595 + 1;\nconst c3597 = c3596 + 1;\nconst c3598 = c3597 + 1;\nconst c3599 = c3598 + 1;\nconst c3600 = c3599 + 1;\nconst c3601 = c3600 + 1;\nconst c3602 = c3601 + 1;\nconst c3603 = c3602 + 1;\nconst c3604 = c3603 + 1;\nconst c3605 = c3604 + 1;\nconst c3606 = c3605 + 1;\nconst c3607 = c3606 + 1;\nconst c3608 = c3607 + 1;\nconst c3609 = c3608 + 1;\nconst c3610 = c3609 + 1;\nconst c3611 = c3610 + 1;\nconst c3612 = c3611 + 1;\nconst c3613 = c3612 + 1;\nconst c3614 = c3613 + 1;\nconst c3615 = c3614 + 1;\nconst c3616 = c3615 + 1;\nconst c3617 = c3616 + 1;\nconst c3618 = c3617 + 1;\nconst c3619 = c3618 + 1;\nconst c3620 = c3619 + 1;\nconst c3621 = c3620 + 1;\nconst c3622 = c3621 + 1;\nconst c3623 = c3622 + 1;\nconst c3624 = c3623 + 1;\nconst c3625 = c3624 + 1;\nconst c3626 = c3625 + 1;\nconst c3627 = c3626 + 1;\nconst c3628 = c3627 + 1;\nconst c3629 = c3628 + 1;\nconst c3630 = c3629 + 1;\nconst c3631 = c3630 + 1;\nconst c3632 = c3631 + 1;\nconst c3633 = c3632 + 1;\nconst c3634 = c3633 + 1;\nconst c3635 = c3634 + 1;\nconst c3636 = c3635 + 1;\nconst c3637 = c3636 + 1;\nconst c3638 = c3637 + 1;\nconst c3639 = c3638 + 1;\nconst c3640 = c3639 + 1;\nconst c3641 = c3640 + 1;\nconst c3642 = c3641 + 1;\nconst c3643 = c3642 + 1;\nconst c3644 = c3643 + 1;\nconst c3645 = c3644 + 1;\nconst c3646 = c3645 + 1;\nconst c3647 = c3646 + 1;\nconst c3648 = c3647 + 1;\nconst c3649 = c3648 + 1;\nconst c3650 = c3649 + 1;\nconst c3651 = c3650 + 1;\nconst c3652 = c3651 + 1;\nconst c3653 = c3652 + 1;\nconst c3654 = c3653 + 1;\nconst c3655 = c3654 + 1;\nconst c3656 = c3655 + 1;\nconst c3657 = c3656 + 1;\nconst c3658 = c3657 + 1;\nconst c3659 = c3658 + 1;\nconst c3660 = c3659 + 1;\nconst c3661 = c3660 + 1;\nconst c3662 = c3661 + 1;\nconst c3663 = c3662 + 1;\nconst c3664 = c3663 + 1;\nconst c3665 = c3664 + 1;\nconst c3666 = c3665 + 1;\nconst c3667 = c3666 + 1;\nconst c3668 = c3667 + 1;\nconst c3669 = c3668 + 1;\nconst c3670 = c3669 + 1;\nconst c3671 = c3670 + 1;\nconst c3672 = c3671 + 1;\nconst c3673 = c3672 + 1;\nconst c3674 = c3673 + 1;\nconst c3675 = c3674 + 1;\nconst c3676 = c3675 + 1;\nconst c3677 = c3676 + 1;\nconst c3678 = c3677 + 1;\nconst c3679 = c3678 + 1;\nconst c3680 = c3679 + 1;\nconst c3681 = c3680 + 1;\nconst c3682 = c3681 + 1;\nconst c3683 = c3682 + 1;\nconst c3684 = c3683 + 1;\nconst c3685 = c3684 + 1;\nconst c3686 = c3685 + 1;\nconst c3687 = c3686 + 1;\nconst c3688 = c3687 + 1;\nconst c3689 = c3688 + 1;\nconst c3690 = c3689 + 1;\nconst c3691 = c3690 + 1;\nconst c3692 = c3691 + 1;\nconst c3693 = c3692 + 1;\nconst c3694 = c3693 + 1;\nconst c3695 = c3694 + 1;\nconst c3696 = c3695 + 1;\nconst c3697 = c3696 + 1;\nconst c3698 = c3697 + 1;\nconst c3699 = c3698 + 1;\nconst c3700 = c3699 + 1;\nconst c3701 = c3700 + 1;\nconst c3702 = c3701 + 1;\nconst c3703 = c3702 + 1;\nconst c3704 = c3703 + 1;\nconst c3705 = c3704 + 1;\nconst c3706 = c3705 + 1;\nconst c3707 = c3706 + 1;\nconst c3708 = c3707 + 1;\nconst c3709 = c3708 + 1;\nconst c3710 = c3709 + 1;\nconst c3711 = c3710 + 1;\nconst c3712 = c3711 + 1;\nconst c3713 = c3712 + 1;\nconst c3714 = c3713 + 1;\nconst c3715 = c3714 + 1;\nconst c3716 = c3715 + 1;\nconst c3717 = c3716 + 1;\nconst c3718 = c3717 + 1;\nconst c3719 = c3718 + 1;\nconst c3720 = c3719 + 1;\nconst c3721 = c3720 + 1;\nconst c3722 = c3721 + 1;\nconst c3723 = c3722 + 1;\nconst c3724 = c3723 + 1;\nconst c3725 = c3724 + 1;\nconst c3726 = c3725 + 1;\nconst c3727 = c3726 + 1;\nconst c3728 = c3727 + 1;\nconst c3729 = c3728 + 1;\nconst c3730 = c3729 + 1;\nconst c3731 = c3730 + 1;\nconst c3732 = c3731 + 1;\nconst c3733 = c3732 + 1;\nconst c3734 = c3733 + 1;\nconst c3735 = c3734 + 1;\nconst c3736 = c3735 + 1;\nconst c3737 = c3736 + 1;\nconst c3738 = c3737 + 1;\nconst c3739 = c3738 + 1;\nconst c3740 = c3739 + 1;\nconst c3741 = c3740 + 1;\nconst c3742 = c3741 + 1;\nconst c3743 = c3742 + 1;\nconst c3744 = c3743 + 1;\nconst c3745 = c3744 + 1;\nconst c3746 = c3745 + 1;\nconst c3747 = c3746 + 1;\nconst c3748 = c3747 + 1;\nconst c3749 = c3748 + 1;\nconst c3750 = c3749 + 1;\nconst c3751 = c3750 + 1;\nconst c3752 = c3751 + 1;\nconst c3753 = c3752 + 1;\nconst c3754 = c3753 + 1;\nconst c3755 = c3754 + 1;\nconst c3756 = c3755 + 1;\nconst c3757 = c3756 + 1;\nconst c3758 = c3757 + 1;\nconst c3759 = c3758 + 1;\nconst c3760 = c3759 + 1;\nconst c3761 = c3760 + 1;\nconst c3762 = c3761 + 1;\nconst c3763 = c3762 + 1;\nconst c3764 = c3763 + 1;\nconst c3765 = c3764 + 1;\nconst c3766 = c3765 + 1;\nconst c3767 = c3766 + 1;\nconst c3768 = c3767 + 1;\nconst c3769 = c3768 + 1;\nconst c3770 = c3769 + 1;\nconst c3771 = c3770 + 1;\nconst c3772 = c3771 + 1;\nconst c3773 = c3772 + 1;\nconst c3774 = c3773 + 1;\nconst c3775 = c3774 + 1;\nconst c3776 = c3775 + 1;\nconst c3777 = c3776 + 1;\nconst c3778 = c3777 + 1;\nconst c3779 = c3778 + 1;\nconst c3780 = c3779 + 1;\nconst c3781 = c3780 + 1;\nconst c3782 = c3781 + 1;\nconst c3783 = c3782 + 1;\nconst c3784 = c3783 + 1;\nconst c3785 = c3784 + 1;\nconst c3786 = c3785 + 1;\nconst c3787 = c3786 + 1;\nconst c3788 = c3787 + 1;\nconst c3789 = c3788 + 1;\nconst c3790 = c3789 + 1;\nconst c3791 = c3790 + 1;\nconst c3792 = c3791 + 1;\nconst c3793 = c3792 + 1;\nconst c3794 = c3793 + 1;\nconst c3795 = c3794 + 1;\nconst c3796 = c3795 + 1;\nconst c3797 = c3796 + 1;\nconst c3798 = c3797 + 1;\nconst c3799 = c3798 + 1;\nconst c3800 = c3799 + 1;\nconst c3801 = c3800 + 1;\nconst c3802 = c3801 + 1;\nconst c3803 = c3802 + 1;\nconst c3804 = c3803 + 1;\nconst c3805 = c3804 + 1;\nconst c3806 = c3805 + 1;\nconst c3807 = c3806 + 1;\nconst c3808 = c3807 + 1;\nconst c3809 = c3808 + 1;\nconst c3810 = c3809 + 1;\nconst c3811 = c3810 + 1;\nconst c3812 = c3811 + 1;\nconst c3813 = c3812 + 1;\nconst c3814 = c3813 + 1;\nconst c3815 = c3814 + 1;\nconst c3816 = c3815 + 1;\nconst c3817 = c3816 + 1;\nconst c3818 = c3817 + 1;\nconst c3819 = c3818 + 1;\nconst c3820 = c3819 + 1;\nconst c3821 = c3820 + 1;\nconst c3822 = c3821 + 1;\nconst c3823 = c3822 + 1;\nconst c3824 = c3823 + 1;\nconst c3825 = c3824 + 1;\nconst c3826 = c3825 + 1;\nconst c3827 = c3826 + 1;\nconst c3828 = c3827 + 1;\nconst c3829 = c3828 + 1;\nconst c3830 = c3829 + 1;\nconst c3831 = c3830 + 1;\nconst c3832 = c3831 + 1;\nconst c3833 = c3832 + 1;\nconst c3834 = c3833 + 1;\nconst c3835 = c3834 + 1;\nconst c3836 = c3835 + 1;\nconst c3837 = c3836 + 1;\nconst c3838 = c3837 + 1;\nconst c3839 = c3838 + 1;\nconst c3840 = c3839 + 1;\nconst c3841 = c3840 + 1;\nconst c3842 = c3841 + 1;\nconst c3843 = c3842 + 1;\nconst c3844 = c3843 + 1;\nconst c3845 = c3844 + 1;\nconst c3846 = c3845 + 1;\nconst c3847 = c3846 + 1;\nconst c3848 = c3847 + 1;\nconst c3849 = c3848 + 1;\nconst c3850 = c3849 + 1;\nconst c3851 = c3850 + 1;\nconst c3852 = c3851 + 1;\nconst c3853 = c3852 + 1;\nconst c3854 = c3853 + 1;\nconst c3855 = c3854 + 1;\nconst c3856 = c3855 + 1;\nconst c3857 = c3856 + 1;\nconst c3858 = c3857 + 1;\nconst c3859 = c3858 + 1;\nconst c3860 = c3859 + 1;\nconst c3861 = c3860 + 1;\nconst c3862 = c3861 + 1;\nconst c3863 = c3862 + 1;\nconst c3864 = c3863 + 1;\nconst c3865 = c3864 + 1;\nconst c3866 = c3865 + 1;\nconst c3867 = c3866 + 1;\nconst c3868 = c3867 + 1;\nconst c3869 = c3868 + 1;\nconst c3870 = c3869 + 1;\nconst c3871 = c3870 + 1;\nconst c3872 = c3871 + 1;\nconst c3873 = c3872 + 1;\nconst c3874 = c3873 + 1;\nconst c3875 = c3874 + 1;\nconst c3876 = c3875 + 1;\nconst c3877 = c3876 + 1;\nconst c3878 = c3877 + 1;\nconst c3879 = c3878 + 1;\nconst c3880 = c3879 + 1;\nconst c3881 = c3880 + 1;\nconst c3882 = c3881 + 1;\nconst c3883 = c3882 + 1;\nconst c3884 = c3883 + 1;\nconst c3885 = c3884 + 1;\nconst c3886 = c3885 + 1;\nconst c3887 = c3886 + 1;\nconst c3888 = c3887 + 1;\nconst c3889 = c3888 + 1;\nconst c3890 = c3889 + 1;\nconst c3891 = c3890 + 1;\nconst c3892 = c3891 + 1;\nconst c3893 = c3892 + 1;\nconst c3894 = c3893 + 1;\nconst c3895 = c3894 + 1;\nconst c3896 = c3895 + 1;\nconst c3897 = c3896 + 1;\nconst c3898 = c3897 + 1;\nconst c3899 = c3898 + 1;\nconst c3900 = c3899 + 1;\nconst c3901 = c3900 + 1;\nconst c3902 = c3901 + 1;\nconst c3903 = c3902 + 1;\nconst c3904 = c3903 + 1;\nconst c3905 = c3904 + 1;\nconst c3906 = c3905 + 1;\nconst c3907 = c3906 + 1;\nconst c3908 = c3907 + 1;\nconst c3909 = c3908 + 1;\nconst c3910 = c3909 + 1;\nconst c3911 = c3910 + 1;\nconst c3912 = c3911 + 1;\nconst c3913 = c3912 + 1;\nconst c3914 = c3913 + 1;\nconst c3915 = c3914 + 1;\nconst c3916 = c3915 + 1;\nconst c3917 = c3916 + 1;\nconst c3918 = c3917 + 1;\nconst c3919 = c3918 + 1;\nconst c3920 = c3919 + 1;\nconst c3921 = c3920 + 1;\nconst c3922 = c3921 + 1;\nconst c3923 = c3922 + 1;\nconst c3924 = c3923 + 1;\nconst c3925 = c3924 + 1;\nconst c3926 = c3925 + 1;\nconst c3927 = c3926 + 1;\nconst c3928 = c3927 + 1;\nconst c3929 = c3928 + 1;\nconst c3930 = c3929 + 1;\nconst c3931 = c3930 + 1;\nconst c3932 = c3931 + 1;\nconst c3933 = c3932 + 1;\nconst c3934 = c3933 + 1;\nconst c3935 = c3934 + 1;\nconst c3936 = c3935 + 1;\nconst c3937 = c3936 + 1;\nconst c3938 = c3937 + 1;\nconst c3939 = c3938 + 1;\nconst c3940 = c3939 + 1;\nconst c3941 = c3940 + 1;\nconst c3942 = c3941 + 1;\nconst c3943 = c3942 + 1;\nconst c3944 = c3943 + 1;\nconst c3945 = c3944 + 1;\nconst c3946 = c3945 + 1;\nconst c3947 = c3946 + 1;\nconst c3948 = c3947 + 1;\nconst c3949 = c3948 + 1;\nconst c3950 = c3949 + 1;\nconst c3951 = c3950 + 1;\nconst c3952 = c3951 + 1;\nconst c3953 = c3952 + 1;\nconst c3954 = c3953 + 1;\nconst c3955 = c3954 + 1;\nconst c3956 = c3955 + 1;\nconst c3957 = c3956 + 1;\nconst c3958 = c3957 + 1;\nconst c3959 = c3958 + 1;\nconst c3960 = c3959 + 1;\nconst c3961 = c3960 + 1;\nconst c3962 = c3961 + 1;\nconst c3963 = c3962 + 1;\nconst c3964 = c3963 + 1;\nconst c3965 = c3964 + 1;\nconst c3966 = c3965 + 1;\nconst c3967 = c3966 + 1;\nconst c3968 = c3967 + 1;\nconst c3969 = c3968 + 1;\nconst c3970 = c3969 + 1;\nconst c3971 = c3970 + 1;\nconst c3972 = c3971 + 1;\nconst c3973 = c3972 + 1;\nconst c3974 = c3973 + 1;\nconst c3975 = c3974 + 1;\nconst c3976 = c3975 + 1;\nconst c3977 = c3976 + 1;\nconst c3978 = c3977 + 1;\nconst c3979 = c3978 + 1;\nconst c3980 = c3979 + 1;\nconst c3981 = c3980 + 1;\nconst c3982 = c3981 + 1;\nconst c3983 = c3982 + 1;\nconst c3984 = c3983 + 1;\nconst c3985 = c3984 + 1;\nconst c3986 = c3985 + 1;\nconst c3987 = c3986 + 1;\nconst c3988 = c3987 + 1;\nconst c3989 = c3988 + 1;\nconst c3990 = c3989 + 1;\nconst c3991 = c3990 + 1;\nconst c3992 = c3991 + 1;\nconst c3993 = c3992 + 1;\nconst c3994 = c3993 + 1;\nconst c3995 = c3994 + 1;\nconst c3996 = c3995 + 1;\nconst c3997 = c3996 + 1;\nconst c3998 = c3997 + 1;\nconst c3999 = c3998 + 1;\nconst c4000 = c3999 + 1;\nconst c4001 = c4000 + 1;\nconst c4002 = c4001 + 1;\nconst c4003 = c4002 + 1;\nconst c4004 = c4003 + 1;\nconst c4005 = c4004 + 1;\nconst c4006 = c4005 + 1;\nconst c4007 = c4006 + 1;\nconst c4008 = c4007 + 1;\nconst c4009 = c4008 + 1;\nconst c4010 = c4009 + 1;\nconst c4011 = c4010 + 1;\nconst c4012 = c4011 + 1;\nconst c4013 = c4012 + 1;\nconst c4014 = c4013 + 1;\nconst c4015 = c4014 + 1;\nconst c4016 = c4015 + 1;\nconst c4017 = c4016 + 1;\nconst c4018 = c4017 + 1;\nconst c4019 = c4018 + 1;\nconst c4020 = c4019 + 1;\nconst c4021 = c4020 + 1;\nconst c4022 = c4021 + 1;\nconst c4023 = c4022 + 1;\nconst c4024 = c4023 + 1;\nconst c4025 = c4024 + 1;\nconst c4026 = c4025 + 1;\nconst c4027 = c4026 + 1;\nconst c4028 = c4027 + 1;\nconst c4029 = c4028 + 1;\nconst c4030 = c4029 + 1;\nconst c4031 = c4030 + 1;\nconst c4032 = c4031 + 1;\nconst c4033 = c4032 + 1;\nconst c4034 = c4033 + 1;\nconst c4035 = c4034 + 1;\nconst c4036 = c4035 + 1;\nconst c4037 = c4036 + 1;\nconst c4038 = c4037 + 1;\nconst c4039 = c4038 + 1;\nconst c4040 = c4039 + 1;\nconst c4041 = c4040 + 1;\nconst c4042 = c4041 + 1;\nconst c4043 = c4042 + 1;\nconst c4044 = c4043 + 1;\nconst c4045 = c4044 + 1;\nconst c4046 = c4045 + 1;\nconst c4047 = c4046 + 1;\nconst c4048 = c4047 + 1;\nconst c4049 = c4048 + 1;\nconst c4050 = c4049 + 1;\nconst c4051 = c4050 + 1;\nconst c4052 = c4051 + 1;\nconst c4053 = c4052 + 1;\nconst c4054 = c4053 + 1;\nconst c4055 = c4054 + 1;\nconst c4056 = c4055 + 1;\nconst c4057 = c4056 + 1;\nconst c4058 = c4057 + 1;\nconst c4059 = c4058 + 1;\nconst c4060 = c4059 + 1;\nconst c4061 = c4060 + 1;\nconst c4062 = c4061 + 1;\nconst c4063 = c4062 + 1;\nconst c4064 = c4063 + 1;\nconst c4065 = c4064 + 1;\nconst c4066 = c4065 + 1;\nconst c4067 = c4066 + 1;\nconst c4068 = c4067 + 1;\nconst c4069 = c4068 + 1;\nconst c4070 = c4069 + 1;\nconst c4071 = c4070 + 1;\nconst c4072 = c4071 + 1;\nconst c4073 = c4072 + 1;\nconst c4074 = c4073 + 1;\nconst c4075 = c4074 + 1;\nconst c4076 = c4075 + 1;\nconst c4077 = c4076 + 1;\nconst c4078 = c4077 + 1;\nconst c4079 = c4078 + 1;\nconst c4080 = c4079 + 1;\nconst c4081 = c4080 + 1;\nconst c4082 = c4081 + 1;\nconst c4083 = c4082 + 1;\nconst c4084 = c4083 + 1;\nconst c4085 = c4084 + 1;\nconst c4086 = c4085 + 1;\nconst c4087 = c4086 + 1;\nconst c4088 = c4087 + 1;\nconst c4089 = c4088 + 1;\nconst c4090 = c4089 + 1;\nconst c4091 = c4090 + 1;\nconst c4092 = c4091 + 1;\nconst c4093 = c4092 + 1;\nconst c4094 = c4093 + 1;\nconst c4095 = c4094 + 1;\nconst c4096 = c4095 + 1;\nconst c4097 = c4096 + 1;\nconst c4098 = c4097 + 1;\nconst c4099 = c4098 + 1;\nconst c4100 = c4099 + 1;\nconst c4101 = c4100 + 1;\nconst c4102 = c4101 + 1;\nconst c4103 = c4102 + 1;\nconst c4104 = c4103 + 1;\nconst c4105 = c4104 + 1;\nconst c4106 = c4105 + 1;\nconst c4107 = c4106 + 1;\nconst c4108 = c4107 + 1;\nconst c4109 = c4108 + 1;\nconst c4110 = c4109 + 1;\nconst c4111 = c4110 + 1;\nconst c4112 = c4111 + 1;\nconst c4113 = c4112 + 1;\nconst c4114 = c4113 + 1;\nconst c4115 = c4114 + 1;\nconst c4116 = c4115 + 1;\nconst c4117 = c4116 + 1;\nconst c4118 = c4117 + 1;\nconst c4119 = c4118 + 1;\nconst c4120 = c4119 + 1;\nconst c4121 = c4120 + 1;\nconst c4122 = c4121 + 1;\nconst c4123 = c4122 + 1;\nconst c4124 = c4123 + 1;\nconst c4125 = c4124 + 1;\nconst c4126 = c4125 + 1;\nconst c4127 = c4126 + 1;\nconst c4128 = c4127 + 1;\nconst c4129 = c4128 + 1;\nconst c4130 = c4129 + 1;\nconst c4131 = c4130 + 1;\nconst c4132 = c4131 + 1;\nconst c4133 = c4132 + 1;\nconst c4134 = c4133 + 1;\nconst c4135 = c4134 + 1;\nconst c4136 = c4135 + 1;\nconst c4137 = c4136 + 1;\nconst c4138 = c4137 + 1;\nconst c4139 = c4138 + 1;\nconst c4140 = c4139 + 1;\nconst c4141 = c4140 + 1;\nconst c4142 = c4141 + 1;\nconst c4143 = c4142 + 1;\nconst c4144 = c4143 + 1;\nconst c4145 = c4144 + 1;\nconst c4146 = c4145 + 1;\nconst c4147 = c4146 + 1;\nconst c4148 = c4147 + 1;\nconst c4149 = c4148 + 1;\nconst c4150 = c4149 + 1;\nconst c4151 = c4150 + 1;\nconst c4152 = c4151 + 1;\nconst c4153 = c4152 + 1;\nconst c4154 = c4153 + 1;\nconst c4155 = c4154 + 1;\nconst c4156 = c4155 + 1;\nconst c4157 = c4156 + 1;\nconst c4158 = c4157 + 1;\nconst c4159 = c4158 + 1;\nconst c4160 = c4159 + 1;\nconst c4161 = c4160 + 1;\nconst c4162 = c4161 + 1;\nconst c4163 = c4162 + 1;\nconst c4164 = c4163 + 1;\nconst c4165 = c4164 + 1;\nconst c4166 = c4165 + 1;\nconst c4167 = c4166 + 1;\nconst c4168 = c4167 + 1;\nconst c4169 = c4168 + 1;\nconst c4170 = c4169 + 1;\nconst c4171 = c4170 + 1;\nconst c4172 = c4171 + 1;\nconst c4173 = c4172 + 1;\nconst c4174 = c4173 + 1;\nconst c4175 = c4174 + 1;\nconst c4176 = c4175 + 1;\nconst c4177 = c4176 + 1;\nconst c4178 = c4177 + 1;\nconst c4179 = c4178 + 1;\nconst c4180 = c4179 + 1;\nconst c4181 = c4180 + 1;\nconst c4182 = c4181 + 1;\nconst c4183 = c4182 + 1;\nconst c4184 = c4183 + 1;\nconst c4185 = c4184 + 1;\nconst c4186 = c4185 + 1;\nconst c4187 = c4186 + 1;\nconst c4188 = c4187 + 1;\nconst c4189 = c4188 + 1;\nconst c4190 = c4189 + 1;\nconst c4191 = c4190 + 1;\nconst c4192 = c4191 + 1;\nconst c4193 = c4192 + 1;\nconst c4194 = c4193 + 1;\nconst c4195 = c4194 + 1;\nconst c4196 = c4195 + 1;\nconst c4197 = c4196 + 1;\nconst c4198 = c4197 + 1;\nconst c4199 = c4198 + 1;\nconst c4200 = c4199 + 1;\nconst c4201 = c4200 + 1;\nconst c4202 = c4201 + 1;\nconst c4203 = c4202 + 1;\nconst c4204 = c4203 + 1;\nconst c4205 = c4204 + 1;\nconst c4206 = c4205 + 1;\nconst c4207 = c4206 + 1;\nconst c4208 = c4207 + 1;\nconst c4209 = c4208 + 1;\nconst c4210 = c4209 + 1;\nconst c4211 = c4210 + 1;\nconst c4212 = c4211 + 1;\nconst c4213 = c4212 + 1;\nconst c4214 = c4213 + 1;\nconst c4215 = c4214 + 1;\nconst c4216 = c4215 + 1;\nconst c4217 = c4216 + 1;\nconst c4218 = c4217 + 1;\nconst c4219 = c4218 + 1;\nconst c4220 = c4219 + 1;\nconst c4221 = c4220 + 1;\nconst c4222 = c4221 + 1;\nconst c4223 = c4222 + 1;\nconst c4224 = c4223 + 1;\nconst c4225 = c4224 + 1;\nconst c4226 = c4225 + 1;\nconst c4227 = c4226 + 1;\nconst c4228 = c4227 + 1;\nconst c4229 = c4228 + 1;\nconst c4230 = c4229 + 1;\nconst c4231 = c4230 + 1;\nconst c4232 = c4231 + 1;\nconst c4233 = c4232 + 1;\nconst c4234 = c4233 + 1;\nconst c4235 = c4234 + 1;\nconst c4236 = c4235 + 1;\nconst c4237 = c4236 + 1;\nconst c4238 = c4237 + 1;\nconst c4239 = c4238 + 1;\nconst c4240 = c4239 + 1;\nconst c4241 = c4240 + 1;\nconst c4242 = c4241 + 1;\nconst c4243 = c4242 + 1;\nconst c4244 = c4243 + 1;\nconst c4245 = c4244 + 1;\nconst c4246 = c4245 + 1;\nconst c4247 = c4246 + 1;\nconst c4248 = c4247 + 1;\nconst c4249 = c4248 + 1;\nconst c4250 = c4249 + 1;\nconst c4251 = c4250 + 1;\nconst c4252 = c4251 + 1;\nconst c4253 = c4252 + 1;\nconst c4254 = c4253 + 1;\nconst c4255 = c4254 + 1;\nconst c4256 = c4255 + 1;\nconst c4257 = c4256 + 1;\nconst c4258 = c4257 + 1;\nconst c4259 = c4258 + 1;\nconst c4260 = c4259 + 1;\nconst c4261 = c4260 + 1;\nconst c4262 = c4261 + 1;\nconst c4263 = c4262 + 1;\nconst c4264 = c4263 + 1;\nconst c4265 = c4264 + 1;\nconst c4266 = c4265 + 1;\nconst c4267 = c4266 + 1;\nconst c4268 = c4267 + 1;\nconst c4269 = c4268 + 1;\nconst c4270 = c4269 + 1;\nconst c4271 = c4270 + 1;\nconst c4272 = c4271 + 1;\nconst c4273 = c4272 + 1;\nconst c4274 = c4273 + 1;\nconst c4275 = c4274 + 1;\nconst c4276 = c4275 + 1;\nconst c4277 = c4276 + 1;\nconst c4278 = c4277 + 1;\nconst c4279 = c4278 + 1;\nconst c4280 = c4279 + 1;\nconst c4281 = c4280 + 1;\nconst c4282 = c4281 + 1;\nconst c4283 = c4282 + 1;\nconst c4284 = c4283 + 1;\nconst c4285 = c4284 + 1;\nconst c4286 = c4285 + 1;\nconst c4287 = c4286 + 1;\nconst c4288 = c4287 + 1;\nconst c4289 = c4288 + 1;\nconst c4290 = c4289 + 1;\nconst c4291 = c4290 + 1;\nconst c4292 = c4291 + 1;\nconst c4293 = c4292 + 1;\nconst c4294 = c4293 + 1;\nconst c4295 = c4294 + 1;\nconst c4296 = c4295 + 1;\nconst c4297 = c4296 + 1;\nconst c4298 = c4297 + 1;\nconst c4299 = c4298 + 1;\nconst c4300 = c4299 + 1;\nconst c4301 = c4300 + 1;\nconst c4302 = c4301 + 1;\nconst c4303 = c4302 + 1;\nconst c4304 = c4303 + 1;\nconst c4305 = c4304 + 1;\nconst c4306 = c4305 + 1;\nconst c4307 = c4306 + 1;\nconst c4308 = c4307 + 1;\nconst c4309 = c4308 + 1;\nconst c4310 = c4309 + 1;\nconst c4311 = c4310 + 1;\nconst c4312 = c4311 + 1;\nconst c4313 = c4312 + 1;\nconst c4314 = c4313 + 1;\nconst c4315 = c4314 + 1;\nconst c4316 = c4315 + 1;\nconst c4317 = c4316 + 1;\nconst c4318 = c4317 + 1;\nconst c4319 = c4318 + 1;\nconst c4320 = c4319 + 1;\nconst c4321 = c4320 + 1;\nconst c4322 = c4321 + 1;\nconst c4323 = c4322 + 1;\nconst c4324 = c4323 + 1;\nconst c4325 = c4324 + 1;\nconst c4326 = c4325 + 1;\nconst c4327 = c4326 + 1;\nconst c4328 = c4327 + 1;\nconst c4329 = c4328 + 1;\nconst c4330 = c4329 + 1;\nconst c4331 = c4330 + 1;\nconst c4332 = c4331 + 1;\nconst c4333 = c4332 + 1;\nconst c4334 = c4333 + 1;\nconst c4335 = c4334 + 1;\nconst c4336 = c4335 + 1;\nconst c4337 = c4336 + 1;\nconst c4338 = c4337 + 1;\nconst c4339 = c4338 + 1;\nconst c4340 = c4339 + 1;\nconst c4341 = c4340 + 1;\nconst c4342 = c4341 + 1;\nconst c4343 = c4342 + 1;\nconst c4344 = c4343 + 1;\nconst c4345 = c4344 + 1;\nconst c4346 = c4345 + 1;\nconst c4347 = c4346 + 1;\nconst c4348 = c4347 + 1;\nconst c4349 = c4348 + 1;\nconst c4350 = c4349 + 1;\nconst c4351 = c4350 + 1;\nconst c4352 = c4351 + 1;\nconst c4353 = c4352 + 1;\nconst c4354 = c4353 + 1;\nconst c4355 = c4354 + 1;\nconst c4356 = c4355 + 1;\nconst c4357 = c4356 + 1;\nconst c4358 = c4357 + 1;\nconst c4359 = c4358 + 1;\nconst c4360 = c4359 + 1;\nconst c4361 = c4360 + 1;\nconst c4362 = c4361 + 1;\nconst c4363 = c4362 + 1;\nconst c4364 = c4363 + 1;\nconst c4365 = c4364 + 1;\nconst c4366 = c4365 + 1;\nconst c4367 = c4366 + 1;\nconst c4368 = c4367 + 1;\nconst c4369 = c4368 + 1;\nconst c4370 = c4369 + 1;\nconst c4371 = c4370 + 1;\nconst c4372 = c4371 + 1;\nconst c4373 = c4372 + 1;\nconst c4374 = c4373 + 1;\nconst c4375 = c4374 + 1;\nconst c4376 = c4375 + 1;\nconst c4377 = c4376 + 1;\nconst c4378 = c4377 + 1;\nconst c4379 = c4378 + 1;\nconst c4380 = c4379 + 1;\nconst c4381 = c4380 + 1;\nconst c4382 = c4381 + 1;\nconst c4383 = c4382 + 1;\nconst c4384 = c4383 + 1;\nconst c4385 = c4384 + 1;\nconst c4386 = c4385 + 1;\nconst c4387 = c4386 + 1;\nconst c4388 = c4387 + 1;\nconst c4389 = c4388 + 1;\nconst c4390 = c4389 + 1;\nconst c4391 = c4390 + 1;\nconst c4392 = c4391 + 1;\nconst c4393 = c4392 + 1;\nconst c4394 = c4393 + 1;\nconst c4395 = c4394 + 1;\nconst c4396 = c4395 + 1;\nconst c4397 = c4396 + 1;\nconst c4398 = c4397 + 1;\nconst c4399 = c4398 + 1;\nconst c4400 = c4399 + 1;\nconst c4401 = c4400 + 1;\nconst c4402 = c4401 + 1;\nconst c4403 = c4402 + 1;\nconst c4404 = c4403 + 1;\nconst c4405 = c4404 + 1;\nconst c4406 = c4405 + 1;\nconst c4407 = c4406 + 1;\nconst c4408 = c4407 + 1;\nconst c4409 = c4408 + 1;\nconst c4410 = c4409 + 1;\nconst c4411 = c4410 + 1;\nconst c4412 = c4411 + 1;\nconst c4413 = c4412 + 1;\nconst c4414 = c4413 + 1;\nconst c4415 = c4414 + 1;\nconst c4416 = c4415 + 1;\nconst c4417 = c4416 + 1;\nconst c4418 = c4417 + 1;\nconst c4419 = c4418 + 1;\nconst c4420 = c4419 + 1;\nconst c4421 = c4420 + 1;\nconst c4422 = c4421 + 1;\nconst c4423 = c4422 + 1;\nconst c4424 = c4423 + 1;\nconst c4425 = c4424 + 1;\nconst c4426 = c4425 + 1;\nconst c4427 = c4426 + 1;\nconst c4428 = c4427 + 1;\nconst c4429 = c4428 + 1;\nconst c4430 = c4429 + 1;\nconst c4431 = c4430 + 1;\nconst c4432 = c4431 + 1;\nconst c4433 = c4432 + 1;\nconst c4434 = c4433 + 1;\nconst c4435 = c4434 + 1;\nconst c4436 = c4435 + 1;\nconst c4437 = c4436 + 1;\nconst c4438 = c4437 + 1;\nconst c4439 = c4438 + 1;\nconst c4440 = c4439 + 1;\nconst c4441 = c4440 + 1;\nconst c4442 = c4441 + 1;\nconst c4443 = c4442 + 1;\nconst c4444 = c4443 + 1;\nconst c4445 = c4444 + 1;\nconst c4446 = c4445 + 1;\nconst c4447 = c4446 + 1;\nconst c4448 = c4447 + 1;\nconst c4449 = c4448 + 1;\nconst c4450 = c4449 + 1;\nconst c4451 = c4450 + 1;\nconst c4452 = c4451 + 1;\nconst c4453 = c4452 + 1;\nconst c4454 = c4453 + 1;\nconst c4455 = c4454 + 1;\nconst c4456 = c4455 + 1;\nconst c4457 = c4456 + 1;\nconst c4458 = c4457 + 1;\nconst c4459 = c4458 + 1;\nconst c4460 = c4459 + 1;\nconst c4461 = c4460 + 1;\nconst c4462 = c4461 + 1;\nconst c4463 = c4462 + 1;\nconst c4464 = c4463 + 1;\nconst c4465 = c4464 + 1;\nconst c4466 = c4465 + 1;\nconst c4467 = c4466 + 1;\nconst c4468 = c4467 + 1;\nconst c4469 = c4468 + 1;\nconst c4470 = c4469 + 1;\nconst c4471 = c4470 + 1;\nconst c4472 = c4471 + 1;\nconst c4473 = c4472 + 1;\nconst c4474 = c4473 + 1;\nconst c4475 = c4474 + 1;\nconst c4476 = c4475 + 1;\nconst c4477 = c4476 + 1;\nconst c4478 = c4477 + 1;\nconst c4479 = c4478 + 1;\nconst c4480 = c4479 + 1;\nconst c4481 = c4480 + 1;\nconst c4482 = c4481 + 1;\nconst c4483 = c4482 + 1;\nconst c4484 = c4483 + 1;\nconst c4485 = c4484 + 1;\nconst c4486 = c4485 + 1;\nconst c4487 = c4486 + 1;\nconst c4488 = c4487 + 1;\nconst c4489 = c4488 + 1;\nconst c4490 = c4489 + 1;\nconst c4491 = c4490 + 1;\nconst c4492 = c4491 + 1;\nconst c4493 = c4492 + 1;\nconst c4494 = c4493 + 1;\nconst c4495 = c4494 + 1;\nconst c4496 = c4495 + 1;\nconst c4497 = c4496 + 1;\nconst c4498 = c4497 + 1;\nconst c4499 = c4498 + 1;\nconst c4500 = c4499 + 1;\nconst c4501 = c4500 + 1;\nconst c4502 = c4501 + 1;\nconst c4503 = c4502 + 1;\nconst c4504 = c4503 + 1;\nconst c4505 = c4504 + 1;\nconst c4506 = c4505 + 1;\nconst c4507 = c4506 + 1;\nconst c4508 = c4507 + 1;\nconst c4509 = c4508 + 1;\nconst c4510 = c4509 + 1;\nconst c4511 = c4510 + 1;\nconst c4512 = c4511 + 1;\nconst c4513 = c4512 + 1;\nconst c4514 = c4513 + 1;\nconst c4515 = c4514 + 1;\nconst c4516 = c4515 + 1;\nconst c4517 = c4516 + 1;\nconst c4518 = c4517 + 1;\nconst c4519 = c4518 + 1;\nconst c4520 = c4519 + 1;\nconst c4521 = c4520 + 1;\nconst c4522 = c4521 + 1;\nconst c4523 = c4522 + 1;\nconst c4524 = c4523 + 1;\nconst c4525 = c4524 + 1;\nconst c4526 = c4525 + 1;\nconst c4527 = c4526 + 1;\nconst c4528 = c4527 + 1;\nconst c4529 = c4528 + 1;\nconst c4530 = c4529 + 1;\nconst c4531 = c4530 + 1;\nconst c4532 = c4531 + 1;\nconst c4533 = c4532 + 1;\nconst c4534 = c4533 + 1;\nconst c4535 = c4534 + 1;\nconst c4536 = c4535 + 1;\nconst c4537 = c4536 + 1;\nconst c4538 = c4537 + 1;\nconst c4539 = c4538 + 1;\nconst c4540 = c4539 + 1;\nconst c4541 = c4540 + 1;\nconst c4542 = c4541 + 1;\nconst c4543 = c4542 + 1;\nconst c4544 = c4543 + 1;\nconst c4545 = c4544 + 1;\nconst c4546 = c4545 + 1;\nconst c4547 = c4546 + 1;\nconst c4548 = c4547 + 1;\nconst c4549 = c4548 + 1;\nconst c4550 = c4549 + 1;\nconst c4551 = c4550 + 1;\nconst c4552 = c4551 + 1;\nconst c4553 = c4552 + 1;\nconst c4554 = c4553 + 1;\nconst c4555 = c4554 + 1;\nconst c4556 = c4555 + 1;\nconst c4557 = c4556 + 1;\nconst c4558 = c4557 + 1;\nconst c4559 = c4558 + 1;\nconst c4560 = c4559 + 1;\nconst c4561 = c4560 + 1;\nconst c4562 = c4561 + 1;\nconst c4563 = c4562 + 1;\nconst c4564 = c4563 + 1;\nconst c4565 = c4564 + 1;\nconst c4566 = c4565 + 1;\nconst c4567 = c4566 + 1;\nconst c4568 = c4567 + 1;\nconst c4569 = c4568 + 1;\nconst c4570 = c4569 + 1;\nconst c4571 = c4570 + 1;\nconst c4572 = c4571 + 1;\nconst c4573 = c4572 + 1;\nconst c4574 = c4573 + 1;\nconst c4575 = c4574 + 1;\nconst c4576 = c4575 + 1;\nconst c4577 = c4576 + 1;\nconst c4578 = c4577 + 1;\nconst c4579 = c4578 + 1;\nconst c4580 = c4579 + 1;\nconst c4581 = c4580 + 1;\nconst c4582 = c4581 + 1;\nconst c4583 = c4582 + 1;\nconst c4584 = c4583 + 1;\nconst c4585 = c4584 + 1;\nconst c4586 = c4585 + 1;\nconst c4587 = c4586 + 1;\nconst c4588 = c4587 + 1;\nconst c4589 = c4588 + 1;\nconst c4590 = c4589 + 1;\nconst c4591 = c4590 + 1;\nconst c4592 = c4591 + 1;\nconst c4593 = c4592 + 1;\nconst c4594 = c4593 + 1;\nconst c4595 = c4594 + 1;\nconst c4596 = c4595 + 1;\nconst c4597 = c4596 + 1;\nconst c4598 = c4597 + 1;\nconst c4599 = c4598 + 1;\nconst c4600 = c4599 + 1;\nconst c4601 = c4600 + 1;\nconst c4602 = c4601 + 1;\nconst c4603 = c4602 + 1;\nconst c4604 = c4603 + 1;\nconst c4605 = c4604 + 1;\nconst c4606 = c4605 + 1;\nconst c4607 = c4606 + 1;\nconst c4608 = c4607 + 1;\nconst c4609 = c4608 + 1;\nconst c4610 = c4609 + 1;\nconst c4611 = c4610 + 1;\nconst c4612 = c4611 + 1;\nconst c4613 = c4612 + 1;\nconst c4614 = c4613 + 1;\nconst c4615 = c4614 + 1;\nconst c4616 = c4615 + 1;\nconst c4617 = c4616 + 1;\nconst c4618 = c4617 + 1;\nconst c4619 = c4618 + 1;\nconst c4620 = c4619 + 1;\nconst c4621 = c4620 + 1;\nconst c4622 = c4621 + 1;\nconst c4623 = c4622 + 1;\nconst c4624 = c4623 + 1;\nconst c4625 = c4624 + 1;\nconst c4626 = c4625 + 1;\nconst c4627 = c4626 + 1;\nconst c4628 = c4627 + 1;\nconst c4629 = c4628 + 1;\nconst c4630 = c4629 + 1;\nconst c4631 = c4630 + 1;\nconst c4632 = c4631 + 1;\nconst c4633 = c4632 + 1;\nconst c4634 = c4633 + 1;\nconst c4635 = c4634 + 1;\nconst c4636 = c4635 + 1;\nconst c4637 = c4636 + 1;\nconst c4638 = c4637 + 1;\nconst c4639 = c4638 + 1;\nconst c4640 = c4639 + 1;\nconst c4641 = c4640 + 1;\nconst c4642 = c4641 + 1;\nconst c4643 = c4642 + 1;\nconst c4644 = c4643 + 1;\nconst c4645 = c4644 + 1;\nconst c4646 = c4645 + 1;\nconst c4647 = c4646 + 1;\nconst c4648 = c4647 + 1;\nconst c4649 = c4648 + 1;\nconst c4650 = c4649 + 1;\nconst c4651 = c4650 + 1;\nconst c4652 = c4651 + 1;\nconst c4653 = c4652 + 1;\nconst c4654 = c4653 + 1;\nconst c4655 = c4654 + 1;\nconst c4656 = c4655 + 1;\nconst c4657 = c4656 + 1;\nconst c4658 = c4657 + 1;\nconst c4659 = c4658 + 1;\nconst c4660 = c4659 + 1;\nconst c4661 = c4660 + 1;\nconst c4662 = c4661 + 1;\nconst c4663 = c4662 + 1;\nconst c4664 = c4663 + 1;\nconst c4665 = c4664 + 1;\nconst c4666 = c4665 + 1;\nconst c4667 = c4666 + 1;\nconst c4668 = c4667 + 1;\nconst c4669 = c4668 + 1;\nconst c4670 = c4669 + 1;\nconst c4671 = c4670 + 1;\nconst c4672 = c4671 + 1;\nconst c4673 = c4672 + 1;\nconst c4674 = c4673 + 1;\nconst c4675 = c4674 + 1;\nconst c4676 = c4675 + 1;\nconst c4677 = c4676 + 1;\nconst c4678 = c4677 + 1;\nconst c4679 = c4678 + 1;\nconst c4680 = c4679 + 1;\nconst c4681 = c4680 + 1;\nconst c4682 = c4681 + 1;\nconst c4683 = c4682 + 1;\nconst c4684 = c4683 + 1;\nconst c4685 = c4684 + 1;\nconst c4686 = c4685 + 1;\nconst c4687 = c4686 + 1;\nconst c4688 = c4687 + 1;\nconst c4689 = c4688 + 1;\nconst c4690 = c4689 + 1;\nconst c4691 = c4690 + 1;\nconst c4692 = c4691 + 1;\nconst c4693 = c4692 + 1;\nconst c4694 = c4693 + 1;\nconst c4695 = c4694 + 1;\nconst c4696 = c4695 + 1;\nconst c4697 = c4696 + 1;\nconst c4698 = c4697 + 1;\nconst c4699 = c4698 + 1;\nconst c4700 = c4699 + 1;\nconst c4701 = c4700 + 1;\nconst c4702 = c4701 + 1;\nconst c4703 = c4702 + 1;\nconst c4704 = c4703 + 1;\nconst c4705 = c4704 + 1;\nconst c4706 = c4705 + 1;\nconst c4707 = c4706 + 1;\nconst c4708 = c4707 + 1;\nconst c4709 = c4708 + 1;\nconst c4710 = c4709 + 1;\nconst c4711 = c4710 + 1;\nconst c4712 = c4711 + 1;\nconst c4713 = c4712 + 1;\nconst c4714 = c4713 + 1;\nconst c4715 = c4714 + 1;\nconst c4716 = c4715 + 1;\nconst c4717 = c4716 + 1;\nconst c4718 = c4717 + 1;\nconst c4719 = c4718 + 1;\nconst c4720 = c4719 + 1;\nconst c4721 = c4720 + 1;\nconst c4722 = c4721 + 1;\nconst c4723 = c4722 + 1;\nconst c4724 = c4723 + 1;\nconst c4725 = c4724 + 1;\nconst c4726 = c4725 + 1;\nconst c4727 = c4726 + 1;\nconst c4728 = c4727 + 1;\nconst c4729 = c4728 + 1;\nconst c4730 = c4729 + 1;\nconst c4731 = c4730 + 1;\nconst c4732 = c4731 + 1;\nconst c4733 = c4732 + 1;\nconst c4734 = c4733 + 1;\nconst c4735 = c4734 + 1;\nconst c4736 = c4735 + 1;\nconst c4737 = c4736 + 1;\nconst c4738 = c4737 + 1;\nconst c4739 = c4738 + 1;\nconst c4740 = c4739 + 1;\nconst c4741 = c4740 + 1;\nconst c4742 = c4741 + 1;\nconst c4743 = c4742 + 1;\nconst c4744 = c4743 + 1;\nconst c4745 = c4744 + 1;\nconst c4746 = c4745 + 1;\nconst c4747 = c4746 + 1;\nconst c4748 = c4747 + 1;\nconst c4749 = c4748 + 1;\nconst c4750 = c4749 + 1;\nconst c4751 = c4750 + 1;\nconst c4752 = c4751 + 1;\nconst c4753 = c4752 + 1;\nconst c4754 = c4753 + 1;\nconst c4755 = c4754 + 1;\nconst c4756 = c4755 + 1;\nconst c4757 = c4756 + 1;\nconst c4758 = c4757 + 1;\nconst c4759 = c4758 + 1;\nconst c4760 = c4759 + 1;\nconst c4761 = c4760 + 1;\nconst c4762 = c4761 + 1;\nconst c4763 = c4762 + 1;\nconst c4764 = c4763 + 1;\nconst c4765 = c4764 + 1;\nconst c4766 = c4765 + 1;\nconst c4767 = c4766 + 1;\nconst c4768 = c4767 + 1;\nconst c4769 = c4768 + 1;\nconst c4770 = c4769 + 1;\nconst c4771 = c4770 + 1;\nconst c4772 = c4771 + 1;\nconst c4773 = c4772 + 1;\nconst c4774 = c4773 + 1;\nconst c4775 = c4774 + 1;\nconst c4776 = c4775 + 1;\nconst c4777 = c4776 + 1;\nconst c4778 = c4777 + 1;\nconst c4779 = c4778 + 1;\nconst c4780 = c4779 + 1;\nconst c4781 = c4780 + 1;\nconst c4782 = c4781 + 1;\nconst c4783 = c4782 + 1;\nconst c4784 = c4783 + 1;\nconst c4785 = c4784 + 1;\nconst c4786 = c4785 + 1;\nconst c4787 = c4786 + 1;\nconst c4788 = c4787 + 1;\nconst c4789 = c4788 + 1;\nconst c4790 = c4789 + 1;\nconst c4791 = c4790 + 1;\nconst c4792 = c4791 + 1;\nconst c4793 = c4792 + 1;\nconst c4794 = c4793 + 1;\nconst c4795 = c4794 + 1;\nconst c4796 = c4795 + 1;\nconst c4797 = c4796 + 1;\nconst c4798 = c4797 + 1;\nconst c4799 = c4798 + 1;\nconst c4800 = c4799 + 1;\nconst c4801 = c4800 + 1;\nconst c4802 = c4801 + 1;\nconst c4803 = c4802 + 1;\nconst c4804 = c4803 + 1;\nconst c4805 = c4804 + 1;\nconst c4806 = c4805 + 1;\nconst c4807 = c4806 + 1;\nconst c4808 = c4807 + 1;\nconst c4809 = c4808 + 1;\nconst c4810 = c4809 + 1;\nconst c4811 = c4810 + 1;\nconst c4812 = c4811 + 1;\nconst c4813 = c4812 + 1;\nconst c4814 = c4813 + 1;\nconst c4815 = c4814 + 1;\nconst c4816 = c4815 + 1;\nconst c4817 = c4816 + 1;\nconst c4818 = c4817 + 1;\nconst c4819 = c4818 + 1;\nconst c4820 = c4819 + 1;\nconst c4821 = c4820 + 1;\nconst c4822 = c4821 + 1;\nconst c4823 = c4822 + 1;\nconst c4824 = c4823 + 1;\nconst c4825 = c4824 + 1;\nconst c4826 = c4825 + 1;\nconst c4827 = c4826 + 1;\nconst c4828 = c4827 + 1;\nconst c4829 = c4828 + 1;\nconst c4830 = c4829 + 1;\nconst c4831 = c4830 + 1;\nconst c4832 = c4831 + 1;\nconst c4833 = c4832 + 1;\nconst c4834 = c4833 + 1;\nconst c4835 = c4834 + 1;\nconst c4836 = c4835 + 1;\nconst c4837 = c4836 + 1;\nconst c4838 = c4837 + 1;\nconst c4839 = c4838 + 1;\nconst c4840 = c4839 + 1;\nconst c4841 = c4840 + 1;\nconst c4842 = c4841 + 1;\nconst c4843 = c4842 + 1;\nconst c4844 = c4843 + 1;\nconst c4845 = c4844 + 1;\nconst c4846 = c4845 + 1;\nconst c4847 = c4846 + 1;\nconst c4848 = c4847 + 1;\nconst c4849 = c4848 + 1;\nconst c4850 = c4849 + 1;\nconst c4851 = c4850 + 1;\nconst c4852 = c4851 + 1;\nconst c4853 = c4852 + 1;\nconst c4854 = c4853 + 1;\nconst c4855 = c4854 + 1;\nconst c4856 = c4855 + 1;\nconst c4857 = c4856 + 1;\nconst c4858 = c4857 + 1;\nconst c4859 = c4858 + 1;\nconst c4860 = c4859 + 1;\nconst c4861 = c4860 + 1;\nconst c4862 = c4861 + 1;\nconst c4863 = c4862 + 1;\nconst c4864 = c4863 + 1;\nconst c4865 = c4864 + 1;\nconst c4866 = c4865 + 1;\nconst c4867 = c4866 + 1;\nconst c4868 = c4867 + 1;\nconst c4869 = c4868 + 1;\nconst c4870 = c4869 + 1;\nconst c4871 = c4870 + 1;\nconst c4872 = c4871 + 1;\nconst c4873 = c4872 + 1;\nconst c4874 = c4873 + 1;\nconst c4875 = c4874 + 1;\nconst c4876 = c4875 + 1;\nconst c4877 = c4876 + 1;\nconst c4878 = c4877 + 1;\nconst c4879 = c4878 + 1;\nconst c4880 = c4879 + 1;\nconst c4881 = c4880 + 1;\nconst c4882 = c4881 + 1;\nconst c4883 = c4882 + 1;\nconst c4884 = c4883 + 1;\nconst c4885 = c4884 + 1;\nconst c4886 = c4885 + 1;\nconst c4887 = c4886 + 1;\nconst c4888 = c4887 + 1;\nconst c4889 = c4888 + 1;\nconst c4890 = c4889 + 1;\nconst c4891 = c4890 + 1;\nconst c4892 = c4891 + 1;\nconst c4893 = c4892 + 1;\nconst c4894 = c4893 + 1;\nconst c4895 = c4894 + 1;\nconst c4896 = c4895 + 1;\nconst c4897 = c4896 + 1;\nconst c4898 = c4897 + 1;\nconst c4899 = c4898 + 1;\nconst c4900 = c4899 + 1;\nconst c4901 = c4900 + 1;\nconst c4902 = c4901 + 1;\nconst c4903 = c4902 + 1;\nconst c4904 = c4903 + 1;\nconst c4905 = c4904 + 1;\nconst c4906 = c4905 + 1;\nconst c4907 = c4906 + 1;\nconst c4908 = c4907 + 1;\nconst c4909 = c4908 + 1;\nconst c4910 = c4909 + 1;\nconst c4911 = c4910 + 1;\nconst c4912 = c4911 + 1;\nconst c4913 = c4912 + 1;\nconst c4914 = c4913 + 1;\nconst c4915 = c4914 + 1;\nconst c4916 = c4915 + 1;\nconst c4917 = c4916 + 1;\nconst c4918 = c4917 + 1;\nconst c4919 = c4918 + 1;\nconst c4920 = c4919 + 1;\nconst c4921 = c4920 + 1;\nconst c4922 = c4921 + 1;\nconst c4923 = c4922 + 1;\nconst c4924 = c4923 + 1;\nconst c4925 = c4924 + 1;\nconst c4926 = c4925 + 1;\nconst c4927 = c4926 + 1;\nconst c4928 = c4927 + 1;\nconst c4929 = c4928 + 1;\nconst c4930 = c4929 + 1;\nconst c4931 = c4930 + 1;\nconst c4932 = c4931 + 1;\nconst c4933 = c4932 + 1;\nconst c4934 = c4933 + 1;\nconst c4935 = c4934 + 1;\nconst c4936 = c4935 + 1;\nconst c4937 = c4936 + 1;\nconst c4938 = c4937 + 1;\nconst c4939 = c4938 + 1;\nconst c4940 = c4939 + 1;\nconst c4941 = c4940 + 1;\nconst c4942 = c4941 + 1;\nconst c4943 = c4942 + 1;\nconst c4944 = c4943 + 1;\nconst c4945 = c4944 + 1;\nconst c4946 = c4945 + 1;\nconst c4947 = c4946 + 1;\nconst c4948 = c4947 + 1;\nconst c4949 = c4948 + 1;\nconst c4950 = c4949 + 1;\nconst c4951 = c4950 + 1;\nconst c4952 = c4951 + 1;\nconst c4953 = c4952 + 1;\nconst c4954 = c4953 + 1;\nconst c4955 = c4954 + 1;\nconst c4956 = c4955 + 1;\nconst c4957 = c4956 + 1;\nconst c4958 = c4957 + 1;\nconst c4959 = c4958 + 1;\nconst c4960 = c4959 + 1;\nconst c4961 = c4960 + 1;\nconst c4962 = c4961 + 1;\nconst c4963 = c4962 + 1;\nconst c4964 = c4963 + 1;\nconst c4965 = c4964 + 1;\nconst c4966 = c4965 + 1;\nconst c4967 = c4966 + 1;\nconst c4968 = c4967 + 1;\nconst c4969 = c4968 + 1;\nconst c4970 = c4969 + 1;\nconst c4971 = c4970 + 1;\nconst c4972 = c4971 + 1;\nconst c4973 = c4972 + 1;\nconst c4974 = c4973 + 1;\nconst c4975 = c4974 + 1;\nconst c4976 = c4975 + 1;\nconst c4977 = c4976 + 1;\nconst c4978 = c4977 + 1;\nconst c4979 = c4978 + 1;\nconst c4980 = c4979 + 1;\nconst c4981 = c4980 + 1;\nconst c4982 = c4981 + 1;\nconst c4983 = c4982 + 1;\nconst c4984 = c4983 + 1;\nconst c4985 = c4984 + 1;\nconst c4986 = c4985 + 1;\nconst c4987 = c4986 + 1;\nconst c4988 = c4987 + 1;\nconst c4989 = c4988 + 1;\nconst c4990 = c4989 + 1;\nconst c4991 = c4990 + 1;\nconst c4992 = c4991 + 1;\nconst c4993 = c4992 + 1;\nconst c4994 = c4993 + 1;\nconst c4995 = c4994 + 1;\nconst c4996 = c4995 + 1;\nconst c4997 = c4996 + 1;\nconst c4998 = c4997 + 1;\nconst c4999 = c4998 + 1;\nconst c5000 = c4999 + 1;\nconst c5001 = c5000 + 1;\nconst c5002 = c5001 + 1;\nconst c5003 = c5002 + 1;\nconst c5004 = c5003 + 1;\nconst c5005 = c5004 + 1;\nconst c5006 = c5005 + 1;\nconst c5007 = c5006 + 1;\nconst c5008 = c5007 + 1;\nconst c5009 = c5008 + 1;\nconst c5010 = c5009 + 1;\nconst c5011 = c5010 + 1;\nconst c5012 = c5011 + 1;\nconst c5013 = c5012 + 1;\nconst c5014 = c5013 + 1;\nconst c5015 = c5014 + 1;\nconst c5016 = c5015 + 1;\nconst c5017 = c5016 + 1;\nconst c5018 = c5017 + 1;\nconst c5019 = c5018 + 1;\nconst c5020 = c5019 + 1;\nconst c5021 = c5020 + 1;\nconst c5022 = c5021 + 1;\nconst c5023 = c5022 + 1;\nconst c5024 = c5023 + 1;\nconst c5025 = c5024 + 1;\nconst c5026 = c5025 + 1;\nconst c5027 = c5026 + 1;\nconst c5028 = c5027 + 1;\nconst c5029 = c5028 + 1;\nconst c5030 = c5029 + 1;\nconst c5031 = c5030 + 1;\nconst c5032 = c5031 + 1;\nconst c5033 = c5032 + 1;\nconst c5034 = c5033 + 1;\nconst c5035 = c5034 + 1;\nconst c5036 = c5035 + 1;\nconst c5037 = c5036 + 1;\nconst c5038 = c5037 + 1;\nconst c5039 = c5038 + 1;\nconst c5040 = c5039 + 1;\nconst c5041 = c5040 + 1;\nconst c5042 = c5041 + 1;\nconst c5043 = c5042 + 1;\nconst c5044 = c5043 + 1;\nconst c5045 = c5044 + 1;\nconst c5046 = c5045 + 1;\nconst c5047 = c5046 + 1;\nconst c5048 = c5047 + 1;\nconst c5049 = c5048 + 1;\nconst c5050 = c5049 + 1;\nconst c5051 = c5050 + 1;\nconst c5052 = c5051 + 1;\nconst c5053 = c5052 + 1;\nconst c5054 = c5053 + 1;\nconst c5055 = c5054 + 1;\nconst c5056 = c5055 + 1;\nconst c5057 = c5056 + 1;\nconst c5058 = c5057 + 1;\nconst c5059 = c5058 + 1;\nconst c5060 = c5059 + 1;\nconst c5061 = c5060 + 1;\nconst c5062 = c5061 + 1;\nconst c5063 = c5062 + 1;\nconst c5064 = c5063 + 1;\nconst c5065 = c5064 + 1;\nconst c5066 = c5065 + 1;\nconst c5067 = c5066 + 1;\nconst c5068 = c5067 + 1;\nconst c5069 = c5068 + 1;\nconst c5070 = c5069 + 1;\nconst c5071 = c5070 + 1;\nconst c5072 = c5071 + 1;\nconst c5073 = c5072 + 1;\nconst c5074 = c5073 + 1;\nconst c5075 = c5074 + 1;\nconst c5076 = c5075 + 1;\nconst c5077 = c5076 + 1;\nconst c5078 = c5077 + 1;\nconst c5079 = c5078 + 1;\nconst c5080 = c5079 + 1;\nconst c5081 = c5080 + 1;\nconst c5082 = c5081 + 1;\nconst c5083 = c5082 + 1;\nconst c5084 = c5083 + 1;\nconst c5085 = c5084 + 1;\nconst c5086 = c5085 + 1;\nconst c5087 = c5086 + 1;\nconst c5088 = c5087 + 1;\nconst c5089 = c5088 + 1;\nconst c5090 = c5089 + 1;\nconst c5091 = c5090 + 1;\nconst c5092 = c5091 + 1;\nconst c5093 = c5092 + 1;\nconst c5094 = c5093 + 1;\nconst c5095 = c5094 + 1;\nconst c5096 = c5095 + 1;\nconst c5097 = c5096 + 1;\nconst c5098 = c5097 + 1;\nconst c5099 = c5098 + 1;\nconst c5100 = c5099 + 1;\nconst c5101 = c5100 + 1;\nconst c5102 = c5101 + 1;\nconst c5103 = c5102 + 1;\nconst c5104 = c5103 + 1;\nconst c5105 = c5104 + 1;\nconst c5106 = c5105 + 1;\nconst c5107 = c5106 + 1;\nconst c5108 = c5107 + 1;\nconst c5109 = c5108 + 1;\nconst c5110 = c5109 + 1;\nconst c5111 = c5110 + 1;\nconst c5112 = c5111 + 1;\nconst c5113 = c5112 + 1;\nconst c5114 = c5113 + 1;\nconst c5115 = c5114 + 1;\nconst c5116 = c5115 + 1;\nconst c5117 = c5116 + 1;\nconst c5118 = c5117 + 1;\nconst c5119 = c5118 + 1;\nconst c5120 = c5119 + 1;\nconst c5121 = c5120 + 1;\nconst c5122 = c5121 + 1;\nconst c5123 = c5122 + 1;\nconst c5124 = c5123 + 1;\nconst c5125 = c5124 + 1;\nconst c5126 = c5125 + 1;\nconst c5127 = c5126 + 1;\nconst c5128 = c5127 + 1;\nconst c5129 = c5128 + 1;\nconst c5130 = c5129 + 1;\nconst c5131 = c5130 + 1;\nconst c5132 = c5131 + 1;\nconst c5133 = c5132 + 1;\nconst c5134 = c5133 + 1;\nconst c5135 = c5134 + 1;\nconst c5136 = c5135 + 1;\nconst c5137 = c5136 + 1;\nconst c5138 = c5137 + 1;\nconst c5139 = c5138 + 1;\nconst c5140 = c5139 + 1;\nconst c5141 = c5140 + 1;\nconst c5142 = c5141 + 1;\nconst c5143 = c5142 + 1;\nconst c5144 = c5143 + 1;\nconst c5145 = c5144 + 1;\nconst c5146 = c5145 + 1;\nconst c5147 = c5146 + 1;\nconst c5148 = c5147 + 1;\nconst c5149 = c5148 + 1;\nconst c5150 = c5149 + 1;\nconst c5151 = c5150 + 1;\nconst c5152 = c5151 + 1;\nconst c5153 = c5152 + 1;\nconst c5154 = c5153 + 1;\nconst c5155 = c5154 + 1;\nconst c5156 = c5155 + 1;\nconst c5157 = c5156 + 1;\nconst c5158 = c5157 + 1;\nconst c5159 = c5158 + 1;\nconst c5160 = c5159 + 1;\nconst c5161 = c5160 + 1;\nconst c5162 = c5161 + 1;\nconst c5163 = c5162 + 1;\nconst c5164 = c5163 + 1;\nconst c5165 = c5164 + 1;\nconst c5166 = c5165 + 1;\nconst c5167 = c5166 + 1;\nconst c5168 = c5167 + 1;\nconst c5169 = c5168 + 1;\nconst c5170 = c5169 + 1;\nconst c5171 = c5170 + 1;\nconst c5172 = c5171 + 1;\nconst c5173 = c5172 + 1;\nconst c5174 = c5173 + 1;\nconst c5175 = c5174 + 1;\nconst c5176 = c5175 + 1;\nconst c5177 = c5176 + 1;\nconst c5178 = c5177 + 1;\nconst c5179 = c5178 + 1;\nconst c5180 = c5179 + 1;\nconst c5181 = c5180 + 1;\nconst c5182 = c5181 + 1;\nconst c5183 = c5182 + 1;\nconst c5184 = c5183 + 1;\nconst c5185 = c5184 + 1;\nconst c5186 = c5185 + 1;\nconst c5187 = c5186 + 1;\nconst c5188 = c5187 + 1;\nconst c5189 = c5188 + 1;\nconst c5190 = c5189 + 1;\nconst c5191 = c5190 + 1;\nconst c5192 = c5191 + 1;\nconst c5193 = c5192 + 1;\nconst c5194 = c5193 + 1;\nconst c5195 = c5194 + 1;\nconst c5196 = c5195 + 1;\nconst c5197 = c5196 + 1;\nconst c5198 = c5197 + 1;\nconst c5199 = c5198 + 1;\nconst c5200 = c5199 + 1;\nconst c5201 = c5200 + 1;\nconst c5202 = c5201 + 1;\nconst c5203 = c5202 + 1;\nconst c5204 = c5203 + 1;\nconst c5205 = c5204 + 1;\nconst c5206 = c5205 + 1;\nconst c5207 = c5206 + 1;\nconst c5208 = c5207 + 1;\nconst c5209 = c5208 + 1;\nconst c5210 = c5209 + 1;\nconst c5211 = c5210 + 1;\nconst c5212 = c5211 + 1;\nconst c5213 = c5212 + 1;\nconst c5214 = c5213 + 1;\nconst c5215 = c5214 + 1;\nconst c5216 = c5215 + 1;\nconst c5217 = c5216 + 1;\nconst c5218 = c5217 + 1;\nconst c5219 = c5218 + 1;\nconst c5220 = c5219 + 1;\nconst c5221 = c5220 + 1;\nconst c5222 = c5221 + 1;\nconst c5223 = c5222 + 1;\nconst c5224 = c5223 + 1;\nconst c5225 = c5224 + 1;\nconst c5226 = c5225 + 1;\nconst c5227 = c5226 + 1;\nconst c5228 = c5227 + 1;\nconst c5229 = c5228 + 1;\nconst c5230 = c5229 + 1;\nconst c5231 = c5230 + 1;\nconst c5232 = c5231 + 1;\nconst c5233 = c5232 + 1;\nconst c5234 = c5233 + 1;\nconst c5235 = c5234 + 1;\nconst c5236 = c5235 + 1;\nconst c5237 = c5236 + 1;\nconst c5238 = c5237 + 1;\nconst c5239 = c5238 + 1;\nconst c5240 = c5239 + 1;\nconst c5241 = c5240 + 1;\nconst c5242 = c5241 + 1;\nconst c5243 = c5242 + 1;\nconst c5244 = c5243 + 1;\nconst c5245 = c5244 + 1;\nconst c5246 = c5245 + 1;\nconst c5247 = c5246 + 1;\nconst c5248 = c5247 + 1;\nconst c5249 = c5248 + 1;\nconst c5250 = c5249 + 1;\nconst c5251 = c5250 + 1;\nconst c5252 = c5251 + 1;\nconst c5253 = c5252 + 1;\nconst c5254 = c5253 + 1;\nconst c5255 = c5254 + 1;\nconst c5256 = c5255 + 1;\nconst c5257 = c5256 + 1;\nconst c5258 = c5257 + 1;\nconst c5259 = c5258 + 1;\nconst c5260 = c5259 + 1;\nconst c5261 = c5260 + 1;\nconst c5262 = c5261 + 1;\nconst c5263 = c5262 + 1;\nconst c5264 = c5263 + 1;\nconst c5265 = c5264 + 1;\nconst c5266 = c5265 + 1;\nconst c5267 = c5266 + 1;\nconst c5268 = c5267 + 1;\nconst c5269 = c5268 + 1;\nconst c5270 = c5269 + 1;\nconst c5271 = c5270 + 1;\nconst c5272 = c5271 + 1;\nconst c5273 = c5272 + 1;\nconst c5274 = c5273 + 1;\nconst c5275 = c5274 + 1;\nconst c5276 = c5275 + 1;\nconst c5277 = c5276 + 1;\nconst c5278 = c5277 + 1;\nconst c5279 = c5278 + 1;\nconst c5280 = c5279 + 1;\nconst c5281 = c5280 + 1;\nconst c5282 = c5281 + 1;\nconst c5283 = c5282 + 1;\nconst c5284 = c5283 + 1;\nconst c5285 = c5284 + 1;\nconst c5286 = c5285 + 1;\nconst c5287 = c5286 + 1;\nconst c5288 = c5287 + 1;\nconst c5289 = c5288 + 1;\nconst c5290 = c5289 + 1;\nconst c5291 = c5290 + 1;\nconst c5292 = c5291 + 1;\nconst c5293 = c5292 + 1;\nconst c5294 = c5293 + 1;\nconst c5295 = c5294 + 1;\nconst c5296 = c5295 + 1;\nconst c5297 = c5296 + 1;\nconst c5298 = c5297 + 1;\nconst c5299 = c5298 + 1;\nconst c5300 = c5299 + 1;\nconst c5301 = c5300 + 1;\nconst c5302 = c5301 + 1;\nconst c5303 = c5302 + 1;\nconst c5304 = c5303 + 1;\nconst c5305 = c5304 + 1;\nconst c5306 = c5305 + 1;\nconst c5307 = c5306 + 1;\nconst c5308 = c5307 + 1;\nconst c5309 = c5308 + 1;\nconst c5310 = c5309 + 1;\nconst c5311 = c5310 + 1;\nconst c5312 = c5311 + 1;\nconst c5313 = c5312 + 1;\nconst c5314 = c5313 + 1;\nconst c5315 = c5314 + 1;\nconst c5316 = c5315 + 1;\nconst c5317 = c5316 + 1;\nconst c5318 = c5317 + 1;\nconst c5319 = c5318 + 1;\nconst c5320 = c5319 + 1;\nconst c5321 = c5320 + 1;\nconst c5322 = c5321 + 1;\nconst c5323 = c5322 + 1;\nconst c5324 = c5323 + 1;\nconst c5325 = c5324 + 1;\nconst c5326 = c5325 + 1;\nconst c5327 = c5326 + 1;\nconst c5328 = c5327 + 1;\nconst c5329 = c5328 + 1;\nconst c5330 = c5329 + 1;\nconst c5331 = c5330 + 1;\nconst c5332 = c5331 + 1;\nconst c5333 = c5332 + 1;\nconst c5334 = c5333 + 1;\nconst c5335 = c5334 + 1;\nconst c5336 = c5335 + 1;\nconst c5337 = c5336 + 1;\nconst c5338 = c5337 + 1;\nconst c5339 = c5338 + 1;\nconst c5340 = c5339 + 1;\nconst c5341 = c5340 + 1;\nconst c5342 = c5341 + 1;\nconst c5343 = c5342 + 1;\nconst c5344 = c5343 + 1;\nconst c5345 = c5344 + 1;\nconst c5346 = c5345 + 1;\nconst c5347 = c5346 + 1;\nconst c5348 = c5347 + 1;\nconst c5349 = c5348 + 1;\nconst c5350 = c5349 + 1;\nconst c5351 = c5350 + 1;\nconst c5352 = c5351 + 1;\nconst c5353 = c5352 + 1;\nconst c5354 = c5353 + 1;\nconst c5355 = c5354 + 1;\nconst c5356 = c5355 + 1;\nconst c5357 = c5356 + 1;\nconst c5358 = c5357 + 1;\nconst c5359 = c5358 + 1;\nconst c5360 = c5359 + 1;\nconst c5361 = c5360 + 1;\nconst c5362 = c5361 + 1;\nconst c5363 = c5362 + 1;\nconst c5364 = c5363 + 1;\nconst c5365 = c5364 + 1;\nconst c5366 = c5365 + 1;\nconst c5367 = c5366 + 1;\nconst c5368 = c5367 + 1;\nconst c5369 = c5368 + 1;\nconst c5370 = c5369 + 1;\nconst c5371 = c5370 + 1;\nconst c5372 = c5371 + 1;\nconst c5373 = c5372 + 1;\nconst c5374 = c5373 + 1;\nconst c5375 = c5374 + 1;\nconst c5376 = c5375 + 1;\nconst c5377 = c5376 + 1;\nconst c5378 = c5377 + 1;\nconst c5379 = c5378 + 1;\nconst c5380 = c5379 + 1;\nconst c5381 = c5380 + 1;\nconst c5382 = c5381 + 1;\nconst c5383 = c5382 + 1;\nconst c5384 = c5383 + 1;\nconst c5385 = c5384 + 1;\nconst c5386 = c5385 + 1;\nconst c5387 = c5386 + 1;\nconst c5388 = c5387 + 1;\nconst c5389 = c5388 + 1;\nconst c5390 = c5389 + 1;\nconst c5391 = c5390 + 1;\nconst c5392 = c5391 + 1;\nconst c5393 = c5392 + 1;\nconst c5394 = c5393 + 1;\nconst c5395 = c5394 + 1;\nconst c5396 = c5395 + 1;\nconst c5397 = c5396 + 1;\nconst c5398 = c5397 + 1;\nconst c5399 = c5398 + 1;\nconst c5400 = c5399 + 1;\nconst c5401 = c5400 + 1;\nconst c5402 = c5401 + 1;\nconst c5403 = c5402 + 1;\nconst c5404 = c5403 + 1;\nconst c5405 = c5404 + 1;\nconst c5406 = c5405 + 1;\nconst c5407 = c5406 + 1;\nconst c5408 = c5407 + 1;\nconst c5409 = c5408 + 1;\nconst c5410 = c5409 + 1;\nconst c5411 = c5410 + 1;\nconst c5412 = c5411 + 1;\nconst c5413 = c5412 + 1;\nconst c5414 = c5413 + 1;\nconst c5415 = c5414 + 1;\nconst c5416 = c5415 + 1;\nconst c5417 = c5416 + 1;\nconst c5418 = c5417 + 1;\nconst c5419 = c5418 + 1;\nconst c5420 = c5419 + 1;\nconst c5421 = c5420 + 1;\nconst c5422 = c5421 + 1;\nconst c5423 = c5422 + 1;\nconst c5424 = c5423 + 1;\nconst c5425 = c5424 + 1;\nconst c5426 = c5425 + 1;\nconst c5427 = c5426 + 1;\nconst c5428 = c5427 + 1;\nconst c5429 = c5428 + 1;\nconst c5430 = c5429 + 1;\nconst c5431 = c5430 + 1;\nconst c5432 = c5431 + 1;\nconst c5433 = c5432 + 1;\nconst c5434 = c5433 + 1;\nconst c5435 = c5434 + 1;\nconst c5436 = c5435 + 1;\nconst c5437 = c5436 + 1;\nconst c5438 = c5437 + 1;\nconst c5439 = c5438 + 1;\nconst c5440 = c5439 + 1;\nconst c5441 = c5440 + 1;\nconst c5442 = c5441 + 1;\nconst c5443 = c5442 + 1;\nconst c5444 = c5443 + 1;\nconst c5445 = c5444 + 1;\nconst c5446 = c5445 + 1;\nconst c5447 = c5446 + 1;\nconst c5448 = c5447 + 1;\nconst c5449 = c5448 + 1;\nconst c5450 = c5449 + 1;\nconst c5451 = c5450 + 1;\nconst c5452 = c5451 + 1;\nconst c5453 = c5452 + 1;\nconst c5454 = c5453 + 1;\nconst c5455 = c5454 + 1;\nconst c5456 = c5455 + 1;\nconst c5457 = c5456 + 1;\nconst c5458 = c5457 + 1;\nconst c5459 = c5458 + 1;\nconst c5460 = c5459 + 1;\nconst c5461 = c5460 + 1;\nconst c5462 = c5461 + 1;\nconst c5463 = c5462 + 1;\nconst c5464 = c5463 + 1;\nconst c5465 = c5464 + 1;\nconst c5466 = c5465 + 1;\nconst c5467 = c5466 + 1;\nconst c5468 = c5467 + 1;\nconst c5469 = c5468 + 1;\nconst c5470 = c5469 + 1;\nconst c5471 = c5470 + 1;\nconst c5472 = c5471 + 1;\nconst c5473 = c5472 + 1;\nconst c5474 = c5473 + 1;\nconst c5475 = c5474 + 1;\nconst c5476 = c5475 + 1;\nconst c5477 = c5476 + 1;\nconst c5478 = c5477 + 1;\nconst c5479 = c5478 + 1;\nconst c5480 = c5479 + 1;\nconst c5481 = c5480 + 1;\nconst c5482 = c5481 + 1;\nconst c5483 = c5482 + 1;\nconst c5484 = c5483 + 1;\nconst c5485 = c5484 + 1;\nconst c5486 = c5485 + 1;\nconst c5487 = c5486 + 1;\nconst c5488 = c5487 + 1;\nconst c5489 = c5488 + 1;\nconst c5490 = c5489 + 1;\nconst c5491 = c5490 + 1;\nconst c5492 = c5491 + 1;\nconst c5493 = c5492 + 1;\nconst c5494 = c5493 + 1;\nconst c5495 = c5494 + 1;\nconst c5496 = c5495 + 1;\nconst c5497 = c5496 + 1;\nconst c5498 = c5497 + 1;\nconst c5499 = c5498 + 1;\nconst c5500 = c5499 + 1;\nconst c5501 = c5500 + 1;\nconst c5502 = c5501 + 1;\nconst c5503 = c5502 + 1;\nconst c5504 = c5503 + 1;\nconst c5505 = c5504 + 1;\nconst c5506 = c5505 + 1;\nconst c5507 = c5506 + 1;\nconst c5508 = c5507 + 1;\nconst c5509 = c5508 + 1;\nconst c5510 = c5509 + 1;\nconst c5511 = c5510 + 1;\nconst c5512 = c5511 + 1;\nconst c5513 = c5512 + 1;\nconst c5514 = c5513 + 1;\nconst c5515 = c5514 + 1;\nconst c5516 = c5515 + 1;\nconst c5517 = c5516 + 1;\nconst c5518 = c5517 + 1;\nconst c5519 = c5518 + 1;\nconst c5520 = c5519 + 1;\nconst c5521 = c5520 + 1;\nconst c5522 = c5521 + 1;\nconst c5523 = c5522 + 1;\nconst c5524 = c5523 + 1;\nconst c5525 = c5524 + 1;\nconst c5526 = c5525 + 1;\nconst c5527 = c5526 + 1;\nconst c5528 = c5527 + 1;\nconst c5529 = c5528 + 1;\nconst c5530 = c5529 + 1;\nconst c5531 = c5530 + 1;\nconst c5532 = c5531 + 1;\nconst c5533 = c5532 + 1;\nconst c5534 = c5533 + 1;\nconst c5535 = c5534 + 1;\nconst c5536 = c5535 + 1;\nconst c5537 = c5536 + 1;\nconst c5538 = c5537 + 1;\nconst c5539 = c5538 + 1;\nconst c5540 = c5539 + 1;\nconst c5541 = c5540 + 1;\nconst c5542 = c5541 + 1;\nconst c5543 = c5542 + 1;\nconst c5544 = c5543 + 1;\nconst c5545 = c5544 + 1;\nconst c5546 = c5545 + 1;\nconst c5547 = c5546 + 1;\nconst c5548 = c5547 + 1;\nconst c5549 = c5548 + 1;\nconst c5550 = c5549 + 1;\nconst c5551 = c5550 + 1;\nconst c5552 = c5551 + 1;\nconst c5553 = c5552 + 1;\nconst c5554 = c5553 + 1;\nconst c5555 = c5554 + 1;\nconst c5556 = c5555 + 1;\nconst c5557 = c5556 + 1;\nconst c5558 = c5557 + 1;\nconst c5559 = c5558 + 1;\nconst c5560 = c5559 + 1;\nconst c5561 = c5560 + 1;\nconst c5562 = c5561 + 1;\nconst c5563 = c5562 + 1;\nconst c5564 = c5563 + 1;\nconst c5565 = c5564 + 1;\nconst c5566 = c5565 + 1;\nconst c5567 = c5566 + 1;\nconst c5568 = c5567 + 1;\nconst c5569 = c5568 + 1;\nconst c5570 = c5569 + 1;\nconst c5571 = c5570 + 1;\nconst c5572 = c5571 + 1;\nconst c5573 = c5572 + 1;\nconst c5574 = c5573 + 1;\nconst c5575 = c5574 + 1;\nconst c5576 = c5575 + 1;\nconst c5577 = c5576 + 1;\nconst c5578 = c5577 + 1;\nconst c5579 = c5578 + 1;\nconst c5580 = c5579 + 1;\nconst c5581 = c5580 + 1;\nconst c5582 = c5581 + 1;\nconst c5583 = c5582 + 1;\nconst c5584 = c5583 + 1;\nconst c5585 = c5584 + 1;\nconst c5586 = c5585 + 1;\nconst c5587 = c5586 + 1;\nconst c5588 = c5587 + 1;\nconst c5589 = c5588 + 1;\nconst c5590 = c5589 + 1;\nconst c5591 = c5590 + 1;\nconst c5592 = c5591 + 1;\nconst c5593 = c5592 + 1;\nconst c5594 = c5593 + 1;\nconst c5595 = c5594 + 1;\nconst c5596 = c5595 + 1;\nconst c5597 = c5596 + 1;\nconst c5598 = c5597 + 1;\nconst c5599 = c5598 + 1;\nconst c5600 = c5599 + 1;\nconst c5601 = c5600 + 1;\nconst c5602 = c5601 + 1;\nconst c5603 = c5602 + 1;\nconst c5604 = c5603 + 1;\nconst c5605 = c5604 + 1;\nconst c5606 = c5605 + 1;\nconst c5607 = c5606 + 1;\nconst c5608 = c5607 + 1;\nconst c5609 = c5608 + 1;\nconst c5610 = c5609 + 1;\nconst c5611 = c5610 + 1;\nconst c5612 = c5611 + 1;\nconst c5613 = c5612 + 1;\nconst c5614 = c5613 + 1;\nconst c5615 = c5614 + 1;\nconst c5616 = c5615 + 1;\nconst c5617 = c5616 + 1;\nconst c5618 = c5617 + 1;\nconst c5619 = c5618 + 1;\nconst c5620 = c5619 + 1;\nconst c5621 = c5620 + 1;\nconst c5622 = c5621 + 1;\nconst c5623 = c5622 + 1;\nconst c5624 = c5623 + 1;\nconst c5625 = c5624 + 1;\nconst c5626 = c5625 + 1;\nconst c5627 = c5626 + 1;\nconst c5628 = c5627 + 1;\nconst c5629 = c5628 + 1;\nconst c5630 = c5629 + 1;\nconst c5631 = c5630 + 1;\nconst c5632 = c5631 + 1;\nconst c5633 = c5632 + 1;\nconst c5634 = c5633 + 1;\nconst c5635 = c5634 + 1;\nconst c5636 = c5635 + 1;\nconst c5637 = c5636 + 1;\nconst c5638 = c5637 + 1;\nconst c5639 = c5638 + 1;\nconst c5640 = c5639 + 1;\nconst c5641 = c5640 + 1;\nconst c5642 = c5641 + 1;\nconst c5643 = c5642 + 1;\nconst c5644 = c5643 + 1;\nconst c5645 = c5644 + 1;\nconst c5646 = c5645 + 1;\nconst c5647 = c5646 + 1;\nconst c5648 = c5647 + 1;\nconst c5649 = c5648 + 1;\nconst c5650 = c5649 + 1;\nconst c5651 = c5650 + 1;\nconst c5652 = c5651 + 1;\nconst c5653 = c5652 + 1;\nconst c5654 = c5653 + 1;\nconst c5655 = c5654 + 1;\nconst c5656 = c5655 + 1;\nconst c5657 = c5656 + 1;\nconst c5658 = c5657 + 1;\nconst c5659 = c5658 + 1;\nconst c5660 = c5659 + 1;\nconst c5661 = c5660 + 1;\nconst c5662 = c5661 + 1;\nconst c5663 = c5662 + 1;\nconst c5664 = c5663 + 1;\nconst c5665 = c5664 + 1;\nconst c5666 = c5665 + 1;\nconst c5667 = c5666 + 1;\nconst c5668 = c5667 + 1;\nconst c5669 = c5668 + 1;\nconst c5670 = c5669 + 1;\nconst c5671 = c5670 + 1;\nconst c5672 = c5671 + 1;\nconst c5673 = c5672 + 1;\nconst c5674 = c5673 + 1;\nconst c5675 = c5674 + 1;\nconst c5676 = c5675 + 1;\nconst c5677 = c5676 + 1;\nconst c5678 = c5677 + 1;\nconst c5679 = c5678 + 1;\nconst c5680 = c5679 + 1;\nconst c5681 = c5680 + 1;\nconst c5682 = c5681 + 1;\nconst c5683 = c5682 + 1;\nconst c5684 = c5683 + 1;\nconst c5685 = c5684 + 1;\nconst c5686 = c5685 + 1;\nconst c5687 = c5686 + 1;\nconst c5688 = c5687 + 1;\nconst c5689 = c5688 + 1;\nconst c5690 = c5689 + 1;\nconst c5691 = c5690 + 1;\nconst c5692 = c5691 + 1;\nconst c5693 = c5692 + 1;\nconst c5694 = c5693 + 1;\nconst c5695 = c5694 + 1;\nconst c5696 = c5695 + 1;\nconst c5697 = c5696 + 1;\nconst c5698 = c5697 + 1;\nconst c5699 = c5698 + 1;\nconst c5700 = c5699 + 1;\nconst c5701 = c5700 + 1;\nconst c5702 = c5701 + 1;\nconst c5703 = c5702 + 1;\nconst c5704 = c5703 + 1;\nconst c5705 = c5704 + 1;\nconst c5706 = c5705 + 1;\nconst c5707 = c5706 + 1;\nconst c5708 = c5707 + 1;\nconst c5709 = c5708 + 1;\nconst c5710 = c5709 + 1;\nconst c5711 = c5710 + 1;\nconst c5712 = c5711 + 1;\nconst c5713 = c5712 + 1;\nconst c5714 = c5713 + 1;\nconst c5715 = c5714 + 1;\nconst c5716 = c5715 + 1;\nconst c5717 = c5716 + 1;\nconst c5718 = c5717 + 1;\nconst c5719 = c5718 + 1;\nconst c5720 = c5719 + 1;\nconst c5721 = c5720 + 1;\nconst c5722 = c5721 + 1;\nconst c5723 = c5722 + 1;\nconst c5724 = c5723 + 1;\nconst c5725 = c5724 + 1;\nconst c5726 = c5725 + 1;\nconst c5727 = c5726 + 1;\nconst c5728 = c5727 + 1;\nconst c5729 = c5728 + 1;\nconst c5730 = c5729 + 1;\nconst c5731 = c5730 + 1;\nconst c5732 = c5731 + 1;\nconst c5733 = c5732 + 1;\nconst c5734 = c5733 + 1;\nconst c5735 = c5734 + 1;\nconst c5736 = c5735 + 1;\nconst c5737 = c5736 + 1;\nconst c5738 = c5737 + 1;\nconst c5739 = c5738 + 1;\nconst c5740 = c5739 + 1;\nconst c5741 = c5740 + 1;\nconst c5742 = c5741 + 1;\nconst c5743 = c5742 + 1;\nconst c5744 = c5743 + 1;\nconst c5745 = c5744 + 1;\nconst c5746 = c5745 + 1;\nconst c5747 = c5746 + 1;\nconst c5748 = c5747 + 1;\nconst c5749 = c5748 + 1;\nconst c5750 = c5749 + 1;\nconst c5751 = c5750 + 1;\nconst c5752 = c5751 + 1;\nconst c5753 = c5752 + 1;\nconst c5754 = c5753 + 1;\nconst c5755 = c5754 + 1;\nconst c5756 = c5755 + 1;\nconst c5757 = c5756 + 1;\nconst c5758 = c5757 + 1;\nconst c5759 = c5758 + 1;\nconst c5760 = c5759 + 1;\nconst c5761 = c5760 + 1;\nconst c5762 = c5761 + 1;\nconst c5763 = c5762 + 1;\nconst c5764 = c5763 + 1;\nconst c5765 = c5764 + 1;\nconst c5766 = c5765 + 1;\nconst c5767 = c5766 + 1;\nconst c5768 = c5767 + 1;\nconst c5769 = c5768 + 1;\nconst c5770 = c5769 + 1;\nconst c5771 = c5770 + 1;\nconst c5772 = c5771 + 1;\nconst c5773 = c5772 + 1;\nconst c5774 = c5773 + 1;\nconst c5775 = c5774 + 1;\nconst c5776 = c5775 + 1;\nconst c5777 = c5776 + 1;\nconst c5778 = c5777 + 1;\nconst c5779 = c5778 + 1;\nconst c5780 = c5779 + 1;\nconst c5781 = c5780 + 1;\nconst c5782 = c5781 + 1;\nconst c5783 = c5782 + 1;\nconst c5784 = c5783 + 1;\nconst c5785 = c5784 + 1;\nconst c5786 = c5785 + 1;\nconst c5787 = c5786 + 1;\nconst c5788 = c5787 + 1;\nconst c5789 = c5788 + 1;\nconst c5790 = c5789 + 1;\nconst c5791 = c5790 + 1;\nconst c5792 = c5791 + 1;\nconst c5793 = c5792 + 1;\nconst c5794 = c5793 + 1;\nconst c5795 = c5794 + 1;\nconst c5796 = c5795 + 1;\nconst c5797 = c5796 + 1;\nconst c5798 = c5797 + 1;\nconst c5799 = c5798 + 1;\nconst c5800 = c5799 + 1;\nconst c5801 = c5800 + 1;\nconst c5802 = c5801 + 1;\nconst c5803 = c5802 + 1;\nconst c5804 = c5803 + 1;\nconst c5805 = c5804 + 1;\nconst c5806 = c5805 + 1;\nconst c5807 = c5806 + 1;\nconst c5808 = c5807 + 1;\nconst c5809 = c5808 + 1;\nconst c5810 = c5809 + 1;\nconst c5811 = c5810 + 1;\nconst c5812 = c5811 + 1;\nconst c5813 = c5812 + 1;\nconst c5814 = c5813 + 1;\nconst c5815 = c5814 + 1;\nconst c5816 = c5815 + 1;\nconst c5817 = c5816 + 1;\nconst c5818 = c5817 + 1;\nconst c5819 = c5818 + 1;\nconst c5820 = c5819 + 1;\nconst c5821 = c5820 + 1;\nconst c5822 = c5821 + 1;\nconst c5823 = c5822 + 1;\nconst c5824 = c5823 + 1;\nconst c5825 = c5824 + 1;\nconst c5826 = c5825 + 1;\nconst c5827 = c5826 + 1;\nconst c5828 = c5827 + 1;\nconst c5829 = c5828 + 1;\nconst c5830 = c5829 + 1;\nconst c5831 = c5830 + 1;\nconst c5832 = c5831 + 1;\nconst c5833 = c5832 + 1;\nconst c5834 = c5833 + 1;\nconst c5835 = c5834 + 1;\nconst c5836 = c5835 + 1;\nconst c5837 = c5836 + 1;\nconst c5838 = c5837 + 1;\nconst c5839 = c5838 + 1;\nconst c5840 = c5839 + 1;\nconst c5841 = c5840 + 1;\nconst c5842 = c5841 + 1;\nconst c5843 = c5842 + 1;\nconst c5844 = c5843 + 1;\nconst c5845 = c5844 + 1;\nconst c5846 = c5845 + 1;\nconst c5847 = c5846 + 1;\nconst c5848 = c5847 + 1;\nconst c5849 = c5848 + 1;\nconst c5850 = c5849 + 1;\nconst c5851 = c5850 + 1;\nconst c5852 = c5851 + 1;\nconst c5853 = c5852 + 1;\nconst c5854 = c5853 + 1;\nconst c5855 = c5854 + 1;\nconst c5856 = c5855 + 1;\nconst c5857 = c5856 + 1;\nconst c5858 = c5857 + 1;\nconst c5859 = c5858 + 1;\nconst c5860 = c5859 + 1;\nconst c5861 = c5860 + 1;\nconst c5862 = c5861 + 1;\nconst c5863 = c5862 + 1;\nconst c5864 = c5863 + 1;\nconst c5865 = c5864 + 1;\nconst c5866 = c5865 + 1;\nconst c5867 = c5866 + 1;\nconst c5868 = c5867 + 1;\nconst c5869 = c5868 + 1;\nconst c5870 = c5869 + 1;\nconst c5871 = c5870 + 1;\nconst c5872 = c5871 + 1;\nconst c5873 = c5872 + 1;\nconst c5874 = c5873 + 1;\nconst c5875 = c5874 + 1;\nconst c5876 = c5875 + 1;\nconst c5877 = c5876 + 1;\nconst c5878 = c5877 + 1;\nconst c5879 = c5878 + 1;\nconst c5880 = c5879 + 1;\nconst c5881 = c5880 + 1;\nconst c5882 = c5881 + 1;\nconst c5883 = c5882 + 1;\nconst c5884 = c5883 + 1;\nconst c5885 = c5884 + 1;\nconst c5886 = c5885 + 1;\nconst c5887 = c5886 + 1;\nconst c5888 = c5887 + 1;\nconst c5889 = c5888 + 1;\nconst c5890 = c5889 + 1;\nconst c5891 = c5890 + 1;\nconst c5892 = c5891 + 1;\nconst c5893 = c5892 + 1;\nconst c5894 = c5893 + 1;\nconst c5895 = c5894 + 1;\nconst c5896 = c5895 + 1;\nconst c5897 = c5896 + 1;\nconst c5898 = c5897 + 1;\nconst c5899 = c5898 + 1;\nconst c5900 = c5899 + 1;\nconst c5901 = c5900 + 1;\nconst c5902 = c5901 + 1;\nconst c5903 = c5902 + 1;\nconst c5904 = c5903 + 1;\nconst c5905 = c5904 + 1;\nconst c5906 = c5905 + 1;\nconst c5907 = c5906 + 1;\nconst c5908 = c5907 + 1;\nconst c5909 = c5908 + 1;\nconst c5910 = c5909 + 1;\nconst c5911 = c5910 + 1;\nconst c5912 = c5911 + 1;\nconst c5913 = c5912 + 1;\nconst c5914 = c5913 + 1;\nconst c5915 = c5914 + 1;\nconst c5916 = c5915 + 1;\nconst c5917 = c5916 + 1;\nconst c5918 = c5917 + 1;\nconst c5919 = c5918 + 1;\nconst c5920 = c5919 + 1;\nconst c5921 = c5920 + 1;\nconst c5922 = c5921 + 1;\nconst c5923 = c5922 + 1;\nconst c5924 = c5923 + 1;\nconst c5925 = c5924 + 1;\nconst c5926 = c5925 + 1;\nconst c5927 = c5926 + 1;\nconst c5928 = c5927 + 1;\nconst c5929 = c5928 + 1;\nconst c5930 = c5929 + 1;\nconst c5931 = c5930 + 1;\nconst c5932 = c5931 + 1;\nconst c5933 = c5932 + 1;\nconst c5934 = c5933 + 1;\nconst c5935 = c5934 + 1;\nconst c5936 = c5935 + 1;\nconst c5937 = c5936 + 1;\nconst c5938 = c5937 + 1;\nconst c5939 = c5938 + 1;\nconst c5940 = c5939 + 1;\nconst c5941 = c5940 + 1;\nconst c5942 = c5941 + 1;\nconst c5943 = c5942 + 1;\nconst c5944 = c5943 + 1;\nconst c5945 = c5944 + 1;\nconst c5946 = c5945 + 1;\nconst c5947 = c5946 + 1;\nconst c5948 = c5947 + 1;\nconst c5949 = c5948 + 1;\nconst c5950 = c5949 + 1;\nconst c5951 = c5950 + 1;\nconst c5952 = c5951 + 1;\nconst c5953 = c5952 + 1;\nconst c5954 = c5953 + 1;\nconst c5955 = c5954 + 1;\nconst c5956 = c5955 + 1;\nconst c5957 = c5956 + 1;\nconst c5958 = c5957 + 1;\nconst c5959 = c5958 + 1;\nconst c5960 = c5959 + 1;\nconst c5961 = c5960 + 1;\nconst c5962 = c5961 + 1;\nconst c5963 = c5962 + 1;\nconst c5964 = c5963 + 1;\nconst c5965 = c5964 + 1;\nconst c5966 = c5965 + 1;\nconst c5967 = c5966 + 1;\nconst c5968 = c5967 + 1;\nconst c5969 = c5968 + 1;\nconst c5970 = c5969 + 1;\nconst c5971 = c5970 + 1;\nconst c5972 = c5971 + 1;\nconst c5973 = c5972 + 1;\nconst c5974 = c5973 + 1;\nconst c5975 = c5974 + 1;\nconst c5976 = c5975 + 1;\nconst c5977 = c5976 + 1;\nconst c5978 = c5977 + 1;\nconst c5979 = c5978 + 1;\nconst c5980 = c5979 + 1;\nconst c5981 = c5980 + 1;\nconst c5982 = c5981 + 1;\nconst c5983 = c5982 + 1;\nconst c5984 = c5983 + 1;\nconst c5985 = c5984 + 1;\nconst c5986 = c5985 + 1;\nconst c5987 = c5986 + 1;\nconst c5988 = c5987 + 1;\nconst c5989 = c5988 + 1;\nconst c5990 = c5989 + 1;\nconst c5991 = c5990 + 1;\nconst c5992 = c5991 + 1;\nconst c5993 = c5992 + 1;\nconst c5994 = c5993 + 1;\nconst c5995 = c5994 + 1;\nconst c5996 = c5995 + 1;\nconst c5997 = c5996 + 1;\nconst c5998 = c5997 + 1;\nconst c5999 = c5998 + 1;\nconst c6000 = c5999 + 1;\nconst c6001 = c6000 + 1;\nconst c6002 = c6001 + 1;\nconst c6003 = c6002 + 1;\nconst c6004 = c6003 + 1;\nconst c6005 = c6004 + 1;\nconst c6006 = c6005 + 1;\nconst c6007 = c6006 + 1;\nconst c6008 = c6007 + 1;\nconst c6009 = c6008 + 1;\nconst c6010 = c6009 + 1;\nconst c6011 = c6010 + 1;\nconst c6012 = c6011 + 1;\nconst c6013 = c6012 + 1;\nconst c6014 = c6013 + 1;\nconst c6015 = c6014 + 1;\nconst c6016 = c6015 + 1;\nconst c6017 = c6016 + 1;\nconst c6018 = c6017 + 1;\nconst c6019 = c6018 + 1;\nconst c6020 = c6019 + 1;\nconst c6021 = c6020 + 1;\nconst c6022 = c6021 + 1;\nconst c6023 = c6022 + 1;\nconst c6024 = c6023 + 1;\nconst c6025 = c6024 + 1;\nconst c6026 = c6025 + 1;\nconst c6027 = c6026 + 1;\nconst c6028 = c6027 + 1;\nconst c6029 = c6028 + 1;\nconst c6030 = c6029 + 1;\nconst c6031 = c6030 + 1;\nconst c6032 = c6031 + 1;\nconst c6033 = c6032 + 1;\nconst c6034 = c6033 + 1;\nconst c6035 = c6034 + 1;\nconst c6036 = c6035 + 1;\nconst c6037 = c6036 + 1;\nconst c6038 = c6037 + 1;\nconst c6039 = c6038 + 1;\nconst c6040 = c6039 + 1;\nconst c6041 = c6040 + 1;\nconst c6042 = c6041 + 1;\nconst c6043 = c6042 + 1;\nconst c6044 = c6043 + 1;\nconst c6045 = c6044 + 1;\nconst c6046 = c6045 + 1;\nconst c6047 = c6046 + 1;\nconst c6048 = c6047 + 1;\nconst c6049 = c6048 + 1;\nconst c6050 = c6049 + 1;\nconst c6051 = c6050 + 1;\nconst c6052 = c6051 + 1;\nconst c6053 = c6052 + 1;\nconst c6054 = c6053 + 1;\nconst c6055 = c6054 + 1;\nconst c6056 = c6055 + 1;\nconst c6057 = c6056 + 1;\nconst c6058 = c6057 + 1;\nconst c6059 = c6058 + 1;\nconst c6060 = c6059 + 1;\nconst c6061 = c6060 + 1;\nconst c6062 = c6061 + 1;\nconst c6063 = c6062 + 1;\nconst c6064 = c6063 + 1;\nconst c6065 = c6064 + 1;\nconst c6066 = c6065 + 1;\nconst c6067 = c6066 + 1;\nconst c6068 = c6067 + 1;\nconst c6069 = c6068 + 1;\nconst c6070 = c6069 + 1;\nconst c6071 = c6070 + 1;\nconst c6072 = c6071 + 1;\nconst c6073 = c6072 + 1;\nconst c6074 = c6073 + 1;\nconst c6075 = c6074 + 1;\nconst c6076 = c6075 + 1;\nconst c6077 = c6076 + 1;\nconst c6078 = c6077 + 1;\nconst c6079 = c6078 + 1;\nconst c6080 = c6079 + 1;\nconst c6081 = c6080 + 1;\nconst c6082 = c6081 + 1;\nconst c6083 = c6082 + 1;\nconst c6084 = c6083 + 1;\nconst c6085 = c6084 + 1;\nconst c6086 = c6085 + 1;\nconst c6087 = c6086 + 1;\nconst c6088 = c6087 + 1;\nconst c6089 = c6088 + 1;\nconst c6090 = c6089 + 1;\nconst c6091 = c6090 + 1;\nconst c6092 = c6091 + 1;\nconst c6093 = c6092 + 1;\nconst c6094 = c6093 + 1;\nconst c6095 = c6094 + 1;\nconst c6096 = c6095 + 1;\nconst c6097 = c6096 + 1;\nconst c6098 = c6097 + 1;\nconst c6099 = c6098 + 1;\nconst c6100 = c6099 + 1;\nconst c6101 = c6100 + 1;\nconst c6102 = c6101 + 1;\nconst c6103 = c6102 + 1;\nconst c6104 = c6103 + 1;\nconst c6105 = c6104 + 1;\nconst c6106 = c6105 + 1;\nconst c6107 = c6106 + 1;\nconst c6108 = c6107 + 1;\nconst c6109 = c6108 + 1;\nconst c6110 = c6109 + 1;\nconst c6111 = c6110 + 1;\nconst c6112 = c6111 + 1;\nconst c6113 = c6112 + 1;\nconst c6114 = c6113 + 1;\nconst c6115 = c6114 + 1;\nconst c6116 = c6115 + 1;\nconst c6117 = c6116 + 1;\nconst c6118 = c6117 + 1;\nconst c6119 = c6118 + 1;\nconst c6120 = c6119 + 1;\nconst c6121 = c6120 + 1;\nconst c6122 = c6121 + 1;\nconst c6123 = c6122 + 1;\nconst c6124 = c6123 + 1;\nconst c6125 = c6124 + 1;\nconst c6126 = c6125 + 1;\nconst c6127 = c6126 + 1;\nconst c6128 = c6127 + 1;\nconst c6129 = c6128 + 1;\nconst c6130 = c6129 + 1;\nconst c6131 = c6130 + 1;\nconst c6132 = c6131 + 1;\nconst c6133 = c6132 + 1;\nconst c6134 = c6133 + 1;\nconst c6135 = c6134 + 1;\nconst c6136 = c6135 + 1;\nconst c6137 = c6136 + 1;\nconst c6138 = c6137 + 1;\nconst c6139 = c6138 + 1;\nconst c6140 = c6139 + 1;\nconst c6141 = c6140 + 1;\nconst c6142 = c6141 + 1;\nconst c6143 = c6142 + 1;\nconst c6144 = c6143 + 1;\nconst c6145 = c6144 + 1;\nconst c6146 = c6145 + 1;\nconst c6147 = c6146 + 1;\nconst c6148 = c6147 + 1;\nconst c6149 = c6148 + 1;\nconst c6150 = c6149 + 1;\nconst c6151 = c6150 + 1;\nconst c6152 = c6151 + 1;\nconst c6153 = c6152 + 1;\nconst c6154 = c6153 + 1;\nconst c6155 = c6154 + 1;\nconst c6156 = c6155 + 1;\nconst c6157 = c6156 + 1;\nconst c6158 = c6157 + 1;\nconst c6159 = c6158 + 1;\nconst c6160 = c6159 + 1;\nconst c6161 = c6160 + 1;\nconst c6162 = c6161 + 1;\nconst c6163 = c6162 + 1;\nconst c6164 = c6163 + 1;\nconst c6165 = c6164 + 1;\nconst c6166 = c6165 + 1;\nconst c6167 = c6166 + 1;\nconst c6168 = c6167 + 1;\nconst c6169 = c6168 + 1;\nconst c6170 = c6169 + 1;\nconst c6171 = c6170 + 1;\nconst c6172 = c6171 + 1;\nconst c6173 = c6172 + 1;\nconst c6174 = c6173 + 1;\nconst c6175 = c6174 + 1;\nconst c6176 = c6175 + 1;\nconst c6177 = c6176 + 1;\nconst c6178 = c6177 + 1;\nconst c6179 = c6178 + 1;\nconst c6180 = c6179 + 1;\nconst c6181 = c6180 + 1;\nconst c6182 = c6181 + 1;\nconst c6183 = c6182 + 1;\nconst c6184 = c6183 + 1;\nconst c6185 = c6184 + 1;\nconst c6186 = c6185 + 1;\nconst c6187 = c6186 + 1;\nconst c6188 = c6187 + 1;\nconst c6189 = c6188 + 1;\nconst c6190 = c6189 + 1;\nconst c6191 = c6190 + 1;\nconst c6192 = c6191 + 1;\nconst c6193 = c6192 + 1;\nconst c6194 = c6193 + 1;\nconst c6195 = c6194 + 1;\nconst c6196 = c6195 + 1;\nconst c6197 = c6196 + 1;\nconst c6198 = c6197 + 1;\nconst c6199 = c6198 + 1;\nconst c6200 = c6199 + 1;\nconst c6201 = c6200 + 1;\nconst c6202 = c6201 + 1;\nconst c6203 = c6202 + 1;\nconst c6204 = c6203 + 1;\nconst c6205 = c6204 + 1;\nconst c6206 = c6205 + 1;\nconst c6207 = c6206 + 1;\nconst c6208 = c6207 + 1;\nconst c6209 = c6208 + 1;\nconst c6210 = c6209 + 1;\nconst c6211 = c6210 + 1;\nconst c6212 = c6211 + 1;\nconst c6213 = c6212 + 1;\nconst c6214 = c6213 + 1;\nconst c6215 = c6214 + 1;\nconst c6216 = c6215 + 1;\nconst c6217 = c6216 + 1;\nconst c6218 = c6217 + 1;\nconst c6219 = c6218 + 1;\nconst c6220 = c6219 + 1;\nconst c6221 = c6220 + 1;\nconst c6222 = c6221 + 1;\nconst c6223 = c6222 + 1;\nconst c6224 = c6223 + 1;\nconst c6225 = c6224 + 1;\nconst c6226 = c6225 + 1;\nconst c6227 = c6226 + 1;\nconst c6228 = c6227 + 1;\nconst c6229 = c6228 + 1;\nconst c6230 = c6229 + 1;\nconst c6231 = c6230 + 1;\nconst c6232 = c6231 + 1;\nconst c6233 = c6232 + 1;\nconst c6234 = c6233 + 1;\nconst c6235 = c6234 + 1;\nconst c6236 = c6235 + 1;\nconst c6237 = c6236 + 1;\nconst c6238 = c6237 + 1;\nconst c6239 = c6238 + 1;\nconst c6240 = c6239 + 1;\nconst c6241 = c6240 + 1;\nconst c6242 = c6241 + 1;\nconst c6243 = c6242 + 1;\nconst c6244 = c6243 + 1;\nconst c6245 = c6244 + 1;\nconst c6246 = c6245 + 1;\nconst c6247 = c6246 + 1;\nconst c6248 = c6247 + 1;\nconst c6249 = c6248 + 1;\nconst c6250 = c6249 + 1;\nconst c6251 = c6250 + 1;\nconst c6252 = c6251 + 1;\nconst c6253 = c6252 + 1;\nconst c6254 = c6253 + 1;\nconst c6255 = c6254 + 1;\nconst c6256 = c6255 + 1;\nconst c6257 = c6256 + 1;\nconst c6258 = c6257 + 1;\nconst c6259 = c6258 + 1;\nconst c6260 = c6259 + 1;\nconst c6261 = c6260 + 1;\nconst c6262 = c6261 + 1;\nconst c6263 = c6262 + 1;\nconst c6264 = c6263 + 1;\nconst c6265 = c6264 + 1;\nconst c6266 = c6265 + 1;\nconst c6267 = c6266 + 1;\nconst c6268 = c6267 + 1;\nconst c6269 = c6268 + 1;\nconst c6270 = c6269 + 1;\nconst c6271 = c6270 + 1;\nconst c6272 = c6271 + 1;\nconst c6273 = c6272 + 1;\nconst c6274 = c6273 + 1;\nconst c6275 = c6274 + 1;\nconst c6276 = c6275 + 1;\nconst c6277 = c6276 + 1;\nconst c6278 = c6277 + 1;\nconst c6279 = c6278 + 1;\nconst c6280 = c6279 + 1;\nconst c6281 = c6280 + 1;\nconst c6282 = c6281 + 1;\nconst c6283 = c6282 + 1;\nconst c6284 = c6283 + 1;\nconst c6285 = c6284 + 1;\nconst c6286 = c6285 + 1;\nconst c6287 = c6286 + 1;\nconst c6288 = c6287 + 1;\nconst c6289 = c6288 + 1;\nconst c6290 = c6289 + 1;\nconst c6291 = c6290 + 1;\nconst c6292 = c6291 + 1;\nconst c6293 = c6292 + 1;\nconst c6294 = c6293 + 1;\nconst c6295 = c6294 + 1;\nconst c6296 = c6295 + 1;\nconst c6297 = c6296 + 1;\nconst c6298 = c6297 + 1;\nconst c6299 = c6298 + 1;\nconst c6300 = c6299 + 1;\nconst c6301 = c6300 + 1;\nconst c6302 = c6301 + 1;\nconst c6303 = c6302 + 1;\nconst c6304 = c6303 + 1;\nconst c6305 = c6304 + 1;\nconst c6306 = c6305 + 1;\nconst c6307 = c6306 + 1;\nconst c6308 = c6307 + 1;\nconst c6309 = c6308 + 1;\nconst c6310 = c6309 + 1;\nconst c6311 = c6310 + 1;\nconst c6312 = c6311 + 1;\nconst c6313 = c6312 + 1;\nconst c6314 = c6313 + 1;\nconst c6315 = c6314 + 1;\nconst c6316 = c6315 + 1;\nconst c6317 = c6316 + 1;\nconst c6318 = c6317 + 1;\nconst c6319 = c6318 + 1;\nconst c6320 = c6319 + 1;\nconst c6321 = c6320 + 1;\nconst c6322 = c6321 + 1;\nconst c6323 = c6322 + 1;\nconst c6324 = c6323 + 1;\nconst c6325 = c6324 + 1;\nconst c6326 = c6325 + 1;\nconst c6327 = c6326 + 1;\nconst c6328 = c6327 + 1;\nconst c6329 = c6328 + 1;\nconst c6330 = c6329 + 1;\nconst c6331 = c6330 + 1;\nconst c6332 = c6331 + 1;\nconst c6333 = c6332 + 1;\nconst c6334 = c6333 + 1;\nconst c6335 = c6334 + 1;\nconst c6336 = c6335 + 1;\nconst c6337 = c6336 + 1;\nconst c6338 = c6337 + 1;\nconst c6339 = c6338 + 1;\nconst c6340 = c6339 + 1;\nconst c6341 = c6340 + 1;\nconst c6342 = c6341 + 1;\nconst c6343 = c6342 + 1;\nconst c6344 = c6343 + 1;\nconst c6345 = c6344 + 1;\nconst c6346 = c6345 + 1;\nconst c6347 = c6346 + 1;\nconst c6348 = c6347 + 1;\nconst c6349 = c6348 + 1;\nconst c6350 = c6349 + 1;\nconst c6351 = c6350 + 1;\nconst c6352 = c6351 + 1;\nconst c6353 = c6352 + 1;\nconst c6354 = c6353 + 1;\nconst c6355 = c6354 + 1;\nconst c6356 = c6355 + 1;\nconst c6357 = c6356 + 1;\nconst c6358 = c6357 + 1;\nconst c6359 = c6358 + 1;\nconst c6360 = c6359 + 1;\nconst c6361 = c6360 + 1;\nconst c6362 = c6361 + 1;\nconst c6363 = c6362 + 1;\nconst c6364 = c6363 + 1;\nconst c6365 = c6364 + 1;\nconst c6366 = c6365 + 1;\nconst c6367 = c6366 + 1;\nconst c6368 = c6367 + 1;\nconst c6369 = c6368 + 1;\nconst c6370 = c6369 + 1;\nconst c6371 = c6370 + 1;\nconst c6372 = c6371 + 1;\nconst c6373 = c6372 + 1;\nconst c6374 = c6373 + 1;\nconst c6375 = c6374 + 1;\nconst c6376 = c6375 + 1;\nconst c6377 = c6376 + 1;\nconst c6378 = c6377 + 1;\nconst c6379 = c6378 + 1;\nconst c6380 = c6379 + 1;\nconst c6381 = c6380 + 1;\nconst c6382 = c6381 + 1;\nconst c6383 = c6382 + 1;\nconst c6384 = c6383 + 1;\nconst c6385 = c6384 + 1;\nconst c6386 = c6385 + 1;\nconst c6387 = c6386 + 1;\nconst c6388 = c6387 + 1;\nconst c6389 = c6388 + 1;\nconst c6390 = c6389 + 1;\nconst c6391 = c6390 + 1;\nconst c6392 = c6391 + 1;\nconst c6393 = c6392 + 1;\nconst c6394 = c6393 + 1;\nconst c6395 = c6394 + 1;\nconst c6396 = c6395 + 1;\nconst c6397 = c6396 + 1;\nconst c6398 = c6397 + 1;\nconst c6399 = c6398 + 1;\nconst c6400 = c6399 + 1;\nconst c6401 = c6400 + 1;\nconst c6402 = c6401 + 1;\nconst c6403 = c6402 + 1;\nconst c6404 = c6403 + 1;\nconst c6405 = c6404 + 1;\nconst c6406 = c6405 + 1;\nconst c6407 = c6406 + 1;\nconst c6408 = c6407 + 1;\nconst c6409 = c6408 + 1;\nconst c6410 = c6409 + 1;\nconst c6411 = c6410 + 1;\nconst c6412 = c6411 + 1;\nconst c6413 = c6412 + 1;\nconst c6414 = c6413 + 1;\nconst c6415 = c6414 + 1;\nconst c6416 = c6415 + 1;\nconst c6417 = c6416 + 1;\nconst c6418 = c6417 + 1;\nconst c6419 = c6418 + 1;\nconst c6420 = c6419 + 1;\nconst c6421 = c6420 + 1;\nconst c6422 = c6421 + 1;\nconst c6423 = c6422 + 1;\nconst c6424 = c6423 + 1;\nconst c6425 = c6424 + 1;\nconst c6426 = c6425 + 1;\nconst c6427 = c6426 + 1;\nconst c6428 = c6427 + 1;\nconst c6429 = c6428 + 1;\nconst c6430 = c6429 + 1;\nconst c6431 = c6430 + 1;\nconst c6432 = c6431 + 1;\nconst c6433 = c6432 + 1;\nconst c6434 = c6433 + 1;\nconst c6435 = c6434 + 1;\nconst c6436 = c6435 + 1;\nconst c6437 = c6436 + 1;\nconst c6438 = c6437 + 1;\nconst c6439 = c6438 + 1;\nconst c6440 = c6439 + 1;\nconst c6441 = c6440 + 1;\nconst c6442 = c6441 + 1;\nconst c6443 = c6442 + 1;\nconst c6444 = c6443 + 1;\nconst c6445 = c6444 + 1;\nconst c6446 = c6445 + 1;\nconst c6447 = c6446 + 1;\nconst c6448 = c6447 + 1;\nconst c6449 = c6448 + 1;\nconst c6450 = c6449 + 1;\nconst c6451 = c6450 + 1;\nconst c6452 = c6451 + 1;\nconst c6453 = c6452 + 1;\nconst c6454 = c6453 + 1;\nconst c6455 = c6454 + 1;\nconst c6456 = c6455 + 1;\nconst c6457 = c6456 + 1;\nconst c6458 = c6457 + 1;\nconst c6459 = c6458 + 1;\nconst c6460 = c6459 + 1;\nconst c6461 = c6460 + 1;\nconst c6462 = c6461 + 1;\nconst c6463 = c6462 + 1;\nconst c6464 = c6463 + 1;\nconst c6465 = c6464 + 1;\nconst c6466 = c6465 + 1;\nconst c6467 = c6466 + 1;\nconst c6468 = c6467 + 1;\nconst c6469 = c6468 + 1;\nconst c6470 = c6469 + 1;\nconst c6471 = c6470 + 1;\nconst c6472 = c6471 + 1;\nconst c6473 = c6472 + 1;\nconst c6474 = c6473 + 1;\nconst c6475 = c6474 + 1;\nconst c6476 = c6475 + 1;\nconst c6477 = c6476 + 1;\nconst c6478 = c6477 + 1;\nconst c6479 = c6478 + 1;\nconst c6480 = c6479 + 1;\nconst c6481 = c6480 + 1;\nconst c6482 = c6481 + 1;\nconst c6483 = c6482 + 1;\nconst c6484 = c6483 + 1;\nconst c6485 = c6484 + 1;\nconst c6486 = c6485 + 1;\nconst c6487 = c6486 + 1;\nconst c6488 = c6487 + 1;\nconst c6489 = c6488 + 1;\nconst c6490 = c6489 + 1;\nconst c6491 = c6490 + 1;\nconst c6492 = c6491 + 1;\nconst c6493 = c6492 + 1;\nconst c6494 = c6493 + 1;\nconst c6495 = c6494 + 1;\nconst c6496 = c6495 + 1;\nconst c6497 = c6496 + 1;\nconst c6498 = c6497 + 1;\nconst c6499 = c6498 + 1;\nconst c6500 = c6499 + 1;\nconst c6501 = c6500 + 1;\nconst c6502 = c6501 + 1;\nconst c6503 = c6502 + 1;\nconst c6504 = c6503 + 1;\nconst c6505 = c6504 + 1;\nconst c6506 = c6505 + 1;\nconst c6507 = c6506 + 1;\nconst c6508 = c6507 + 1;\nconst c6509 = c6508 + 1;\nconst c6510 = c6509 + 1;\nconst c6511 = c6510 + 1;\nconst c6512 = c6511 + 1;\nconst c6513 = c6512 + 1;\nconst c6514 = c6513 + 1;\nconst c6515 = c6514 + 1;\nconst c6516 = c6515 + 1;\nconst c6517 = c6516 + 1;\nconst c6518 = c6517 + 1;\nconst c6519 = c6518 + 1;\nconst c6520 = c6519 + 1;\nconst c6521 = c6520 + 1;\nconst c6522 = c6521 + 1;\nconst c6523 = c6522 + 1;\nconst c6524 = c6523 + 1;\nconst c6525 = c6524 + 1;\nconst c6526 = c6525 + 1;\nconst c6527 = c6526 + 1;\nconst c6528 = c6527 + 1;\nconst c6529 = c6528 + 1;\nconst c6530 = c6529 + 1;\nconst c6531 = c6530 + 1;\nconst c6532 = c6531 + 1;\nconst c6533 = c6532 + 1;\nconst c6534 = c6533 + 1;\nconst c6535 = c6534 + 1;\nconst c6536 = c6535 + 1;\nconst c6537 = c6536 + 1;\nconst c6538 = c6537 + 1;\nconst c6539 = c6538 + 1;\nconst c6540 = c6539 + 1;\nconst c6541 = c6540 + 1;\nconst c6542 = c6541 + 1;\nconst c6543 = c6542 + 1;\nconst c6544 = c6543 + 1;\nconst c6545 = c6544 + 1;\nconst c6546 = c6545 + 1;\nconst c6547 = c6546 + 1;\nconst c6548 = c6547 + 1;\nconst c6549 = c6548 + 1;\nconst c6550 = c6549 + 1;\nconst c6551 = c6550 + 1;\nconst c6552 = c6551 + 1;\nconst c6553 = c6552 + 1;\nconst c6554 = c6553 + 1;\nconst c6555 = c6554 + 1;\nconst c6556 = c6555 + 1;\nconst c6557 = c6556 + 1;\nconst c6558 = c6557 + 1;\nconst c6559 = c6558 + 1;\nconst c6560 = c6559 + 1;\nconst c6561 = c6560 + 1;\nconst c6562 = c6561 + 1;\nconst c6563 = c6562 + 1;\nconst c6564 = c6563 + 1;\nconst c6565 = c6564 + 1;\nconst c6566 = c6565 + 1;\nconst c6567 = c6566 + 1;\nconst c6568 = c6567 + 1;\nconst c6569 = c6568 + 1;\nconst c6570 = c6569 + 1;\nconst c6571 = c6570 + 1;\nconst c6572 = c6571 + 1;\nconst c6573 = c6572 + 1;\nconst c6574 = c6573 + 1;\nconst c6575 = c6574 + 1;\nconst c6576 = c6575 + 1;\nconst c6577 = c6576 + 1;\nconst c6578 = c6577 + 1;\nconst c6579 = c6578 + 1;\nconst c6580 = c6579 + 1;\nconst c6581 = c6580 + 1;\nconst c6582 = c6581 + 1;\nconst c6583 = c6582 + 1;\nconst c6584 = c6583 + 1;\nconst c6585 = c6584 + 1;\nconst c6586 = c6585 + 1;\nconst c6587 = c6586 + 1;\nconst c6588 = c6587 + 1;\nconst c6589 = c6588 + 1;\nconst c6590 = c6589 + 1;\nconst c6591 = c6590 + 1;\nconst c6592 = c6591 + 1;\nconst c6593 = c6592 + 1;\nconst c6594 = c6593 + 1;\nconst c6595 = c6594 + 1;\nconst c6596 = c6595 + 1;\nconst c6597 = c6596 + 1;\nconst c6598 = c6597 + 1;\nconst c6599 = c6598 + 1;\nconst c6600 = c6599 + 1;\nconst c6601 = c6600 + 1;\nconst c6602 = c6601 + 1;\nconst c6603 = c6602 + 1;\nconst c6604 = c6603 + 1;\nconst c6605 = c6604 + 1;\nconst c6606 = c6605 + 1;\nconst c6607 = c6606 + 1;\nconst c6608 = c6607 + 1;\nconst c6609 = c6608 + 1;\nconst c6610 = c6609 + 1;\nconst c6611 = c6610 + 1;\nconst c6612 = c6611 + 1;\nconst c6613 = c6612 + 1;\nconst c6614 = c6613 + 1;\nconst c6615 = c6614 + 1;\nconst c6616 = c6615 + 1;\nconst c6617 = c6616 + 1;\nconst c6618 = c6617 + 1;\nconst c6619 = c6618 + 1;\nconst c6620 = c6619 + 1;\nconst c6621 = c6620 + 1;\nconst c6622 = c6621 + 1;\nconst c6623 = c6622 + 1;\nconst c6624 = c6623 + 1;\nconst c6625 = c6624 + 1;\nconst c6626 = c6625 + 1;\nconst c6627 = c6626 + 1;\nconst c6628 = c6627 + 1;\nconst c6629 = c6628 + 1;\nconst c6630 = c6629 + 1;\nconst c6631 = c6630 + 1;\nconst c6632 = c6631 + 1;\nconst c6633 = c6632 + 1;\nconst c6634 = c6633 + 1;\nconst c6635 = c6634 + 1;\nconst c6636 = c6635 + 1;\nconst c6637 = c6636 + 1;\nconst c6638 = c6637 + 1;\nconst c6639 = c6638 + 1;\nconst c6640 = c6639 + 1;\nconst c6641 = c6640 + 1;\nconst c6642 = c6641 + 1;\nconst c6643 = c6642 + 1;\nconst c6644 = c6643 + 1;\nconst c6645 = c6644 + 1;\nconst c6646 = c6645 + 1;\nconst c6647 = c6646 + 1;\nconst c6648 = c6647 + 1;\nconst c6649 = c6648 + 1;\nconst c6650 = c6649 + 1;\nconst c6651 = c6650 + 1;\nconst c6652 = c6651 + 1;\nconst c6653 = c6652 + 1;\nconst c6654 = c6653 + 1;\nconst c6655 = c6654 + 1;\nconst c6656 = c6655 + 1;\nconst c6657 = c6656 + 1;\nconst c6658 = c6657 + 1;\nconst c6659 = c6658 + 1;\nconst c6660 = c6659 + 1;\nconst c6661 = c6660 + 1;\nconst c6662 = c6661 + 1;\nconst c6663 = c6662 + 1;\nconst c6664 = c6663 + 1;\nconst c6665 = c6664 + 1;\nconst c6666 = c6665 + 1;\nconst c6667 = c6666 + 1;\nconst c6668 = c6667 + 1;\nconst c6669 = c6668 + 1;\nconst c6670 = c6669 + 1;\nconst c6671 = c6670 + 1;\nconst c6672 = c6671 + 1;\nconst c6673 = c6672 + 1;\nconst c6674 = c6673 + 1;\nconst c6675 = c6674 + 1;\nconst c6676 = c6675 + 1;\nconst c6677 = c6676 + 1;\nconst c6678 = c6677 + 1;\nconst c6679 = c6678 + 1;\nconst c6680 = c6679 + 1;\nconst c6681 = c6680 + 1;\nconst c6682 = c6681 + 1;\nconst c6683 = c6682 + 1;\nconst c6684 = c6683 + 1;\nconst c6685 = c6684 + 1;\nconst c6686 = c6685 + 1;\nconst c6687 = c6686 + 1;\nconst c6688 = c6687 + 1;\nconst c6689 = c6688 + 1;\nconst c6690 = c6689 + 1;\nconst c6691 = c6690 + 1;\nconst c6692 = c6691 + 1;\nconst c6693 = c6692 + 1;\nconst c6694 = c6693 + 1;\nconst c6695 = c6694 + 1;\nconst c6696 = c6695 + 1;\nconst c6697 = c6696 + 1;\nconst c6698 = c6697 + 1;\nconst c6699 = c6698 + 1;\nconst c6700 = c6699 + 1;\nconst c6701 = c6700 + 1;\nconst c6702 = c6701 + 1;\nconst c6703 = c6702 + 1;\nconst c6704 = c6703 + 1;\nconst c6705 = c6704 + 1;\nconst c6706 = c6705 + 1;\nconst c6707 = c6706 + 1;\nconst c6708 = c6707 + 1;\nconst c6709 = c6708 + 1;\nconst c6710 = c6709 + 1;\nconst c6711 = c6710 + 1;\nconst c6712 = c6711 + 1;\nconst c6713 = c6712 + 1;\nconst c6714 = c6713 + 1;\nconst c6715 = c6714 + 1;\nconst c6716 = c6715 + 1;\nconst c6717 = c6716 + 1;\nconst c6718 = c6717 + 1;\nconst c6719 = c6718 + 1;\nconst c6720 = c6719 + 1;\nconst c6721 = c6720 + 1;\nconst c6722 = c6721 + 1;\nconst c6723 = c6722 + 1;\nconst c6724 = c6723 + 1;\nconst c6725 = c6724 + 1;\nconst c6726 = c6725 + 1;\nconst c6727 = c6726 + 1;\nconst c6728 = c6727 + 1;\nconst c6729 = c6728 + 1;\nconst c6730 = c6729 + 1;\nconst c6731 = c6730 + 1;\nconst c6732 = c6731 + 1;\nconst c6733 = c6732 + 1;\nconst c6734 = c6733 + 1;\nconst c6735 = c6734 + 1;\nconst c6736 = c6735 + 1;\nconst c6737 = c6736 + 1;\nconst c6738 = c6737 + 1;\nconst c6739 = c6738 + 1;\nconst c6740 = c6739 + 1;\nconst c6741 = c6740 + 1;\nconst c6742 = c6741 + 1;\nconst c6743 = c6742 + 1;\nconst c6744 = c6743 + 1;\nconst c6745 = c6744 + 1;\nconst c6746 = c6745 + 1;\nconst c6747 = c6746 + 1;\nconst c6748 = c6747 + 1;\nconst c6749 = c6748 + 1;\nconst c6750 = c6749 + 1;\nconst c6751 = c6750 + 1;\nconst c6752 = c6751 + 1;\nconst c6753 = c6752 + 1;\nconst c6754 = c6753 + 1;\nconst c6755 = c6754 + 1;\nconst c6756 = c6755 + 1;\nconst c6757 = c6756 + 1;\nconst c6758 = c6757 + 1;\nconst c6759 = c6758 + 1;\nconst c6760 = c6759 + 1;\nconst c6761 = c6760 + 1;\nconst c6762 = c6761 + 1;\nconst c6763 = c6762 + 1;\nconst c6764 = c6763 + 1;\nconst c6765 = c6764 + 1;\nconst c6766 = c6765 + 1;\nconst c6767 = c6766 + 1;\nconst c6768 = c6767 + 1;\nconst c6769 = c6768 + 1;\nconst c6770 = c6769 + 1;\nconst c6771 = c6770 + 1;\nconst c6772 = c6771 + 1;\nconst c6773 = c6772 + 1;\nconst c6774 = c6773 + 1;\nconst c6775 = c6774 + 1;\nconst c6776 = c6775 + 1;\nconst c6777 = c6776 + 1;\nconst c6778 = c6777 + 1;\nconst c6779 = c6778 + 1;\nconst c6780 = c6779 + 1;\nconst c6781 = c6780 + 1;\nconst c6782 = c6781 + 1;\nconst c6783 = c6782 + 1;\nconst c6784 = c6783 + 1;\nconst c6785 = c6784 + 1;\nconst c6786 = c6785 + 1;\nconst c6787 = c6786 + 1;\nconst c6788 = c6787 + 1;\nconst c6789 = c6788 + 1;\nconst c6790 = c6789 + 1;\nconst c6791 = c6790 + 1;\nconst c6792 = c6791 + 1;\nconst c6793 = c6792 + 1;\nconst c6794 = c6793 + 1;\nconst c6795 = c6794 + 1;\nconst c6796 = c6795 + 1;\nconst c6797 = c6796 + 1;\nconst c6798 = c6797 + 1;\nconst c6799 = c6798 + 1;\nconst c6800 = c6799 + 1;\nconst c6801 = c6800 + 1;\nconst c6802 = c6801 + 1;\nconst c6803 = c6802 + 1;\nconst c6804 = c6803 + 1;\nconst c6805 = c6804 + 1;\nconst c6806 = c6805 + 1;\nconst c6807 = c6806 + 1;\nconst c6808 = c6807 + 1;\nconst c6809 = c6808 + 1;\nconst c6810 = c6809 + 1;\nconst c6811 = c6810 + 1;\nconst c6812 = c6811 + 1;\nconst c6813 = c6812 + 1;\nconst c6814 = c6813 + 1;\nconst c6815 = c6814 + 1;\nconst c6816 = c6815 + 1;\nconst c6817 = c6816 + 1;\nconst c6818 = c6817 + 1;\nconst c6819 = c6818 + 1;\nconst c6820 = c6819 + 1;\nconst c6821 = c6820 + 1;\nconst c6822 = c6821 + 1;\nconst c6823 = c6822 + 1;\nconst c6824 = c6823 + 1;\nconst c6825 = c6824 + 1;\nconst c6826 = c6825 + 1;\nconst c6827 = c6826 + 1;\nconst c6828 = c6827 + 1;\nconst c6829 = c6828 + 1;\nconst c6830 = c6829 + 1;\nconst c6831 = c6830 + 1;\nconst c6832 = c6831 + 1;\nconst c6833 = c6832 + 1;\nconst c6834 = c6833 + 1;\nconst c6835 = c6834 + 1;\nconst c6836 = c6835 + 1;\nconst c6837 = c6836 + 1;\nconst c6838 = c6837 + 1;\nconst c6839 = c6838 + 1;\nconst c6840 = c6839 + 1;\nconst c6841 = c6840 + 1;\nconst c6842 = c6841 + 1;\nconst c6843 = c6842 + 1;\nconst c6844 = c6843 + 1;\nconst c6845 = c6844 + 1;\nconst c6846 = c6845 + 1;\nconst c6847 = c6846 + 1;\nconst c6848 = c6847 + 1;\nconst c6849 = c6848 + 1;\nconst c6850 = c6849 + 1;\nconst c6851 = c6850 + 1;\nconst c6852 = c6851 + 1;\nconst c6853 = c6852 + 1;\nconst c6854 = c6853 + 1;\nconst c6855 = c6854 + 1;\nconst c6856 = c6855 + 1;\nconst c6857 = c6856 + 1;\nconst c6858 = c6857 + 1;\nconst c6859 = c6858 + 1;\nconst c6860 = c6859 + 1;\nconst c6861 = c6860 + 1;\nconst c6862 = c6861 + 1;\nconst c6863 = c6862 + 1;\nconst c6864 = c6863 + 1;\nconst c6865 = c6864 + 1;\nconst c6866 = c6865 + 1;\nconst c6867 = c6866 + 1;\nconst c6868 = c6867 + 1;\nconst c6869 = c6868 + 1;\nconst c6870 = c6869 + 1;\nconst c6871 = c6870 + 1;\nconst c6872 = c6871 + 1;\nconst c6873 = c6872 + 1;\nconst c6874 = c6873 + 1;\nconst c6875 = c6874 + 1;\nconst c6876 = c6875 + 1;\nconst c6877 = c6876 + 1;\nconst c6878 = c6877 + 1;\nconst c6879 = c6878 + 1;\nconst c6880 = c6879 + 1;\nconst c6881 = c6880 + 1;\nconst c6882 = c6881 + 1;\nconst c6883 = c6882 + 1;\nconst c6884 = c6883 + 1;\nconst c6885 = c6884 + 1;\nconst c6886 = c6885 + 1;\nconst c6887 = c6886 + 1;\nconst c6888 = c6887 + 1;\nconst c6889 = c6888 + 1;\nconst c6890 = c6889 + 1;\nconst c6891 = c6890 + 1;\nconst c6892 = c6891 + 1;\nconst c6893 = c6892 + 1;\nconst c6894 = c6893 + 1;\nconst c6895 = c6894 + 1;\nconst c6896 = c6895 + 1;\nconst c6897 = c6896 + 1;\nconst c6898 = c6897 + 1;\nconst c6899 = c6898 + 1;\nconst c6900 = c6899 + 1;\nconst c6901 = c6900 + 1;\nconst c6902 = c6901 + 1;\nconst c6903 = c6902 + 1;\nconst c6904 = c6903 + 1;\nconst c6905 = c6904 + 1;\nconst c6906 = c6905 + 1;\nconst c6907 = c6906 + 1;\nconst c6908 = c6907 + 1;\nconst c6909 = c6908 + 1;\nconst c6910 = c6909 + 1;\nconst c6911 = c6910 + 1;\nconst c6912 = c6911 + 1;\nconst c6913 = c6912 + 1;\nconst c6914 = c6913 + 1;\nconst c6915 = c6914 + 1;\nconst c6916 = c6915 + 1;\nconst c6917 = c6916 + 1;\nconst c6918 = c6917 + 1;\nconst c6919 = c6918 + 1;\nconst c6920 = c6919 + 1;\nconst c6921 = c6920 + 1;\nconst c6922 = c6921 + 1;\nconst c6923 = c6922 + 1;\nconst c6924 = c6923 + 1;\nconst c6925 = c6924 + 1;\nconst c6926 = c6925 + 1;\nconst c6927 = c6926 + 1;\nconst c6928 = c6927 + 1;\nconst c6929 = c6928 + 1;\nconst c6930 = c6929 + 1;\nconst c6931 = c6930 + 1;\nconst c6932 = c6931 + 1;\nconst c6933 = c6932 + 1;\nconst c6934 = c6933 + 1;\nconst c6935 = c6934 + 1;\nconst c6936 = c6935 + 1;\nconst c6937 = c6936 + 1;\nconst c6938 = c6937 + 1;\nconst c6939 = c6938 + 1;\nconst c6940 = c6939 + 1;\nconst c6941 = c6940 + 1;\nconst c6942 = c6941 + 1;\nconst c6943 = c6942 + 1;\nconst c6944 = c6943 + 1;\nconst c6945 = c6944 + 1;\nconst c6946 = c6945 + 1;\nconst c6947 = c6946 + 1;\nconst c6948 = c6947 + 1;\nconst c6949 = c6948 + 1;\nconst c6950 = c6949 + 1;\nconst c6951 = c6950 + 1;\nconst c6952 = c6951 + 1;\nconst c6953 = c6952 + 1;\nconst c6954 = c6953 + 1;\nconst c6955 = c6954 + 1;\nconst c6956 = c6955 + 1;\nconst c6957 = c6956 + 1;\nconst c6958 = c6957 + 1;\nconst c6959 = c6958 + 1;\nconst c6960 = c6959 + 1;\nconst c6961 = c6960 + 1;\nconst c6962 = c6961 + 1;\nconst c6963 = c6962 + 1;\nconst c6964 = c6963 + 1;\nconst c6965 = c6964 + 1;\nconst c6966 = c6965 + 1;\nconst c6967 = c6966 + 1;\nconst c6968 = c6967 + 1;\nconst c6969 = c6968 + 1;\nconst c6970 = c6969 + 1;\nconst c6971 = c6970 + 1;\nconst c6972 = c6971 + 1;\nconst c6973 = c6972 + 1;\nconst c6974 = c6973 + 1;\nconst c6975 = c6974 + 1;\nconst c6976 = c6975 + 1;\nconst c6977 = c6976 + 1;\nconst c6978 = c6977 + 1;\nconst c6979 = c6978 + 1;\nconst c6980 = c6979 + 1;\nconst c6981 = c6980 + 1;\nconst c6982 = c6981 + 1;\nconst c6983 = c6982 + 1;\nconst c6984 = c6983 + 1;\nconst c6985 = c6984 + 1;\nconst c6986 = c6985 + 1;\nconst c6987 = c6986 + 1;\nconst c6988 = c6987 + 1;\nconst c6989 = c6988 + 1;\nconst c6990 = c6989 + 1;\nconst c6991 = c6990 + 1;\nconst c6992 = c6991 + 1;\nconst c6993 = c6992 + 1;\nconst c6994 = c6993 + 1;\nconst c6995 = c6994 + 1;\nconst c6996 = c6995 + 1;\nconst c6997 = c6996 + 1;\nconst c6998 = c6997 + 1;\nconst c6999 = c6998 + 1;\nconst c7000 = c6999 + 1;\nconst c7001 = c7000 + 1;\nconst c7002 = c7001 + 1;\nconst c7003 = c7002 + 1;\nconst c7004 = c7003 + 1;\nconst c7005 = c7004 + 1;\nconst c7006 = c7005 + 1;\nconst c7007 = c7006 + 1;\nconst c7008 = c7007 + 1;\nconst c7009 = c7008 + 1;\nconst c7010 = c7009 + 1;\nconst c7011 = c7010 + 1;\nconst c7012 = c7011 + 1;\nconst c7013 = c7012 + 1;\nconst c7014 = c7013 + 1;\nconst c7015 = c7014 + 1;\nconst c7016 = c7015 + 1;\nconst c7017 = c7016 + 1;\nconst c7018 = c7017 + 1;\nconst c7019 = c7018 + 1;\nconst c7020 = c7019 + 1;\nconst c7021 = c7020 + 1;\nconst c7022 = c7021 + 1;\nconst c7023 = c7022 + 1;\nconst c7024 = c7023 + 1;\nconst c7025 = c7024 + 1;\nconst c7026 = c7025 + 1;\nconst c7027 = c7026 + 1;\nconst c7028 = c7027 + 1;\nconst c7029 = c7028 + 1;\nconst c7030 = c7029 + 1;\nconst c7031 = c7030 + 1;\nconst c7032 = c7031 + 1;\nconst c7033 = c7032 + 1;\nconst c7034 = c7033 + 1;\nconst c7035 = c7034 + 1;\nconst c7036 = c7035 + 1;\nconst c7037 = c7036 + 1;\nconst c7038 = c7037 + 1;\nconst c7039 = c7038 + 1;\nconst c7040 = c7039 + 1;\nconst c7041 = c7040 + 1;\nconst c7042 = c7041 + 1;\nconst c7043 = c7042 + 1;\nconst c7044 = c7043 + 1;\nconst c7045 = c7044 + 1;\nconst c7046 = c7045 + 1;\nconst c7047 = c7046 + 1;\nconst c7048 = c7047 + 1;\nconst c7049 = c7048 + 1;\nconst c7050 = c7049 + 1;\nconst c7051 = c7050 + 1;\nconst c7052 = c7051 + 1;\nconst c7053 = c7052 + 1;\nconst c7054 = c7053 + 1;\nconst c7055 = c7054 + 1;\nconst c7056 = c7055 + 1;\nconst c7057 = c7056 + 1;\nconst c7058 = c7057 + 1;\nconst c7059 = c7058 + 1;\nconst c7060 = c7059 + 1;\nconst c7061 = c7060 + 1;\nconst c7062 = c7061 + 1;\nconst c7063 = c7062 + 1;\nconst c7064 = c7063 + 1;\nconst c7065 = c7064 + 1;\nconst c7066 = c7065 + 1;\nconst c7067 = c7066 + 1;\nconst c7068 = c7067 + 1;\nconst c7069 = c7068 + 1;\nconst c7070 = c7069 + 1;\nconst c7071 = c7070 + 1;\nconst c7072 = c7071 + 1;\nconst c7073 = c7072 + 1;\nconst c7074 = c7073 + 1;\nconst c7075 = c7074 + 1;\nconst c7076 = c7075 + 1;\nconst c7077 = c7076 + 1;\nconst c7078 = c7077 + 1;\nconst c7079 = c7078 + 1;\nconst c7080 = c7079 + 1;\nconst c7081 = c7080 + 1;\nconst c7082 = c7081 + 1;\nconst c7083 = c7082 + 1;\nconst c7084 = c7083 + 1;\nconst c7085 = c7084 + 1;\nconst c7086 = c7085 + 1;\nconst c7087 = c7086 + 1;\nconst c7088 = c7087 + 1;\nconst c7089 = c7088 + 1;\nconst c7090 = c7089 + 1;\nconst c7091 = c7090 + 1;\nconst c7092 = c7091 + 1;\nconst c7093 = c7092 + 1;\nconst c7094 = c7093 + 1;\nconst c7095 = c7094 + 1;\nconst c7096 = c7095 + 1;\nconst c7097 = c7096 + 1;\nconst c7098 = c7097 + 1;\nconst c7099 = c7098 + 1;\nconst c7100 = c7099 + 1;\nconst c7101 = c7100 + 1;\nconst c7102 = c7101 + 1;\nconst c7103 = c7102 + 1;\nconst c7104 = c7103 + 1;\nconst c7105 = c7104 + 1;\nconst c7106 = c7105 + 1;\nconst c7107 = c7106 + 1;\nconst c7108 = c7107 + 1;\nconst c7109 = c7108 + 1;\nconst c7110 = c7109 + 1;\nconst c7111 = c7110 + 1;\nconst c7112 = c7111 + 1;\nconst c7113 = c7112 + 1;\nconst c7114 = c7113 + 1;\nconst c7115 = c7114 + 1;\nconst c7116 = c7115 + 1;\nconst c7117 = c7116 + 1;\nconst c7118 = c7117 + 1;\nconst c7119 = c7118 + 1;\nconst c7120 = c7119 + 1;\nconst c7121 = c7120 + 1;\nconst c7122 = c7121 + 1;\nconst c7123 = c7122 + 1;\nconst c7124 = c7123 + 1;\nconst c7125 = c7124 + 1;\nconst c7126 = c7125 + 1;\nconst c7127 = c7126 + 1;\nconst c7128 = c7127 + 1;\nconst c7129 = c7128 + 1;\nconst c7130 = c7129 + 1;\nconst c7131 = c7130 + 1;\nconst c7132 = c7131 + 1;\nconst c7133 = c7132 + 1;\nconst c7134 = c7133 + 1;\nconst c7135 = c7134 + 1;\nconst c7136 = c7135 + 1;\nconst c7137 = c7136 + 1;\nconst c7138 = c7137 + 1;\nconst c7139 = c7138 + 1;\nconst c7140 = c7139 + 1;\nconst c7141 = c7140 + 1;\nconst c7142 = c7141 + 1;\nconst c7143 = c7142 + 1;\nconst c7144 = c7143 + 1;\nconst c7145 = c7144 + 1;\nconst c7146 = c7145 + 1;\nconst c7147 = c7146 + 1;\nconst c7148 = c7147 + 1;\nconst c7149 = c7148 + 1;\nconst c7150 = c7149 + 1;\nconst c7151 = c7150 + 1;\nconst c7152 = c7151 + 1;\nconst c7153 = c7152 + 1;\nconst c7154 = c7153 + 1;\nconst c7155 = c7154 + 1;\nconst c7156 = c7155 + 1;\nconst c7157 = c7156 + 1;\nconst c7158 = c7157 + 1;\nconst c7159 = c7158 + 1;\nconst c7160 = c7159 + 1;\nconst c7161 = c7160 + 1;\nconst c7162 = c7161 + 1;\nconst c7163 = c7162 + 1;\nconst c7164 = c7163 + 1;\nconst c7165 = c7164 + 1;\nconst c7166 = c7165 + 1;\nconst c7167 = c7166 + 1;\nconst c7168 = c7167 + 1;\nconst c7169 = c7168 + 1;\nconst c7170 = c7169 + 1;\nconst c7171 = c7170 + 1;\nconst c7172 = c7171 + 1;\nconst c7173 = c7172 + 1;\nconst c7174 = c7173 + 1;\nconst c7175 = c7174 + 1;\nconst c7176 = c7175 + 1;\nconst c7177 = c7176 + 1;\nconst c7178 = c7177 + 1;\nconst c7179 = c7178 + 1;\nconst c7180 = c7179 + 1;\nconst c7181 = c7180 + 1;\nconst c7182 = c7181 + 1;\nconst c7183 = c7182 + 1;\nconst c7184 = c7183 + 1;\nconst c7185 = c7184 + 1;\nconst c7186 = c7185 + 1;\nconst c7187 = c7186 + 1;\nconst c7188 = c7187 + 1;\nconst c7189 = c7188 + 1;\nconst c7190 = c7189 + 1;\nconst c7191 = c7190 + 1;\nconst c7192 = c7191 + 1;\nconst c7193 = c7192 + 1;\nconst c7194 = c7193 + 1;\nconst c7195 = c7194 + 1;\nconst c7196 = c7195 + 1;\nconst c7197 = c7196 + 1;\nconst c7198 = c7197 + 1;\nconst c7199 = c7198 + 1;\nconst c7200 = c7199 + 1;\nconst c7201 = c7200 + 1;\nconst c7202 = c7201 + 1;\nconst c7203 = c7202 + 1;\nconst c7204 = c7203 + 1;\nconst c7205 = c7204 + 1;\nconst c7206 = c7205 + 1;\nconst c7207 = c7206 + 1;\nconst c7208 = c7207 + 1;\nconst c7209 = c7208 + 1;\nconst c7210 = c7209 + 1;\nconst c7211 = c7210 + 1;\nconst c7212 = c7211 + 1;\nconst c7213 = c7212 + 1;\nconst c7214 = c7213 + 1;\nconst c7215 = c7214 + 1;\nconst c7216 = c7215 + 1;\nconst c7217 = c7216 + 1;\nconst c7218 = c7217 + 1;\nconst c7219 = c7218 + 1;\nconst c7220 = c7219 + 1;\nconst c7221 = c7220 + 1;\nconst c7222 = c7221 + 1;\nconst c7223 = c7222 + 1;\nconst c7224 = c7223 + 1;\nconst c7225 = c7224 + 1;\nconst c7226 = c7225 + 1;\nconst c7227 = c7226 + 1;\nconst c7228 = c7227 + 1;\nconst c7229 = c7228 + 1;\nconst c7230 = c7229 + 1;\nconst c7231 = c7230 + 1;\nconst c7232 = c7231 + 1;\nconst c7233 = c7232 + 1;\nconst c7234 = c7233 + 1;\nconst c7235 = c7234 + 1;\nconst c7236 = c7235 + 1;\nconst c7237 = c7236 + 1;\nconst c7238 = c7237 + 1;\nconst c7239 = c7238 + 1;\nconst c7240 = c7239 + 1;\nconst c7241 = c7240 + 1;\nconst c7242 = c7241 + 1;\nconst c7243 = c7242 + 1;\nconst c7244 = c7243 + 1;\nconst c7245 = c7244 + 1;\nconst c7246 = c7245 + 1;\nconst c7247 = c7246 + 1;\nconst c7248 = c7247 + 1;\nconst c7249 = c7248 + 1;\nconst c7250 = c7249 + 1;\nconst c7251 = c7250 + 1;\nconst c7252 = c7251 + 1;\nconst c7253 = c7252 + 1;\nconst c7254 = c7253 + 1;\nconst c7255 = c7254 + 1;\nconst c7256 = c7255 + 1;\nconst c7257 = c7256 + 1;\nconst c7258 = c7257 + 1;\nconst c7259 = c7258 + 1;\nconst c7260 = c7259 + 1;\nconst c7261 = c7260 + 1;\nconst c7262 = c7261 + 1;\nconst c7263 = c7262 + 1;\nconst c7264 = c7263 + 1;\nconst c7265 = c7264 + 1;\nconst c7266 = c7265 + 1;\nconst c7267 = c7266 + 1;\nconst c7268 = c7267 + 1;\nconst c7269 = c7268 + 1;\nconst c7270 = c7269 + 1;\nconst c7271 = c7270 + 1;\nconst c7272 = c7271 + 1;\nconst c7273 = c7272 + 1;\nconst c7274 = c7273 + 1;\nconst c7275 = c7274 + 1;\nconst c7276 = c7275 + 1;\nconst c7277 = c7276 + 1;\nconst c7278 = c7277 + 1;\nconst c7279 = c7278 + 1;\nconst c7280 = c7279 + 1;\nconst c7281 = c7280 + 1;\nconst c7282 = c7281 + 1;\nconst c7283 = c7282 + 1;\nconst c7284 = c7283 + 1;\nconst c7285 = c7284 + 1;\nconst c7286 = c7285 + 1;\nconst c7287 = c7286 + 1;\nconst c7288 = c7287 + 1;\nconst c7289 = c7288 + 1;\nconst c7290 = c7289 + 1;\nconst c7291 = c7290 + 1;\nconst c7292 = c7291 + 1;\nconst c7293 = c7292 + 1;\nconst c7294 = c7293 + 1;\nconst c7295 = c7294 + 1;\nconst c7296 = c7295 + 1;\nconst c7297 = c7296 + 1;\nconst c7298 = c7297 + 1;\nconst c7299 = c7298 + 1;\nconst c7300 = c7299 + 1;\nconst c7301 = c7300 + 1;\nconst c7302 = c7301 + 1;\nconst c7303 = c7302 + 1;\nconst c7304 = c7303 + 1;\nconst c7305 = c7304 + 1;\nconst c7306 = c7305 + 1;\nconst c7307 = c7306 + 1;\nconst c7308 = c7307 + 1;\nconst c7309 = c7308 + 1;\nconst c7310 = c7309 + 1;\nconst c7311 = c7310 + 1;\nconst c7312 = c7311 + 1;\nconst c7313 = c7312 + 1;\nconst c7314 = c7313 + 1;\nconst c7315 = c7314 + 1;\nconst c7316 = c7315 + 1;\nconst c7317 = c7316 + 1;\nconst c7318 = c7317 + 1;\nconst c7319 = c7318 + 1;\nconst c7320 = c7319 + 1;\nconst c7321 = c7320 + 1;\nconst c7322 = c7321 + 1;\nconst c7323 = c7322 + 1;\nconst c7324 = c7323 + 1;\nconst c7325 = c7324 + 1;\nconst c7326 = c7325 + 1;\nconst c7327 = c7326 + 1;\nconst c7328 = c7327 + 1;\nconst c7329 = c7328 + 1;\nconst c7330 = c7329 + 1;\nconst c7331 = c7330 + 1;\nconst c7332 = c7331 + 1;\nconst c7333 = c7332 + 1;\nconst c7334 = c7333 + 1;\nconst c7335 = c7334 + 1;\nconst c7336 = c7335 + 1;\nconst c7337 = c7336 + 1;\nconst c7338 = c7337 + 1;\nconst c7339 = c7338 + 1;\nconst c7340 = c7339 + 1;\nconst c7341 = c7340 + 1;\nconst c7342 = c7341 + 1;\nconst c7343 = c7342 + 1;\nconst c7344 = c7343 + 1;\nconst c7345 = c7344 + 1;\nconst c7346 = c7345 + 1;\nconst c7347 = c7346 + 1;\nconst c7348 = c7347 + 1;\nconst c7349 = c7348 + 1;\nconst c7350 = c7349 + 1;\nconst c7351 = c7350 + 1;\nconst c7352 = c7351 + 1;\nconst c7353 = c7352 + 1;\nconst c7354 = c7353 + 1;\nconst c7355 = c7354 + 1;\nconst c7356 = c7355 + 1;\nconst c7357 = c7356 + 1;\nconst c7358 = c7357 + 1;\nconst c7359 = c7358 + 1;\nconst c7360 = c7359 + 1;\nconst c7361 = c7360 + 1;\nconst c7362 = c7361 + 1;\nconst c7363 = c7362 + 1;\nconst c7364 = c7363 + 1;\nconst c7365 = c7364 + 1;\nconst c7366 = c7365 + 1;\nconst c7367 = c7366 + 1;\nconst c7368 = c7367 + 1;\nconst c7369 = c7368 + 1;\nconst c7370 = c7369 + 1;\nconst c7371 = c7370 + 1;\nconst c7372 = c7371 + 1;\nconst c7373 = c7372 + 1;\nconst c7374 = c7373 + 1;\nconst c7375 = c7374 + 1;\nconst c7376 = c7375 + 1;\nconst c7377 = c7376 + 1;\nconst c7378 = c7377 + 1;\nconst c7379 = c7378 + 1;\nconst c7380 = c7379 + 1;\nconst c7381 = c7380 + 1;\nconst c7382 = c7381 + 1;\nconst c7383 = c7382 + 1;\nconst c7384 = c7383 + 1;\nconst c7385 = c7384 + 1;\nconst c7386 = c7385 + 1;\nconst c7387 = c7386 + 1;\nconst c7388 = c7387 + 1;\nconst c7389 = c7388 + 1;\nconst c7390 = c7389 + 1;\nconst c7391 = c7390 + 1;\nconst c7392 = c7391 + 1;\nconst c7393 = c7392 + 1;\nconst c7394 = c7393 + 1;\nconst c7395 = c7394 + 1;\nconst c7396 = c7395 + 1;\nconst c7397 = c7396 + 1;\nconst c7398 = c7397 + 1;\nconst c7399 = c7398 + 1;\nconst c7400 = c7399 + 1;\nconst c7401 = c7400 + 1;\nconst c7402 = c7401 + 1;\nconst c7403 = c7402 + 1;\nconst c7404 = c7403 + 1;\nconst c7405 = c7404 + 1;\nconst c7406 = c7405 + 1;\nconst c7407 = c7406 + 1;\nconst c7408 = c7407 + 1;\nconst c7409 = c7408 + 1;\nconst c7410 = c7409 + 1;\nconst c7411 = c7410 + 1;\nconst c7412 = c7411 + 1;\nconst c7413 = c7412 + 1;\nconst c7414 = c7413 + 1;\nconst c7415 = c7414 + 1;\nconst c7416 = c7415 + 1;\nconst c7417 = c7416 + 1;\nconst c7418 = c7417 + 1;\nconst c7419 = c7418 + 1;\nconst c7420 = c7419 + 1;\nconst c7421 = c7420 + 1;\nconst c7422 = c7421 + 1;\nconst c7423 = c7422 + 1;\nconst c7424 = c7423 + 1;\nconst c7425 = c7424 + 1;\nconst c7426 = c7425 + 1;\nconst c7427 = c7426 + 1;\nconst c7428 = c7427 + 1;\nconst c7429 = c7428 + 1;\nconst c7430 = c7429 + 1;\nconst c7431 = c7430 + 1;\nconst c7432 = c7431 + 1;\nconst c7433 = c7432 + 1;\nconst c7434 = c7433 + 1;\nconst c7435 = c7434 + 1;\nconst c7436 = c7435 + 1;\nconst c7437 = c7436 + 1;\nconst c7438 = c7437 + 1;\nconst c7439 = c7438 + 1;\nconst c7440 = c7439 + 1;\nconst c7441 = c7440 + 1;\nconst c7442 = c7441 + 1;\nconst c7443 = c7442 + 1;\nconst c7444 = c7443 + 1;\nconst c7445 = c7444 + 1;\nconst c7446 = c7445 + 1;\nconst c7447 = c7446 + 1;\nconst c7448 = c7447 + 1;\nconst c7449 = c7448 + 1;\nconst c7450 = c7449 + 1;\nconst c7451 = c7450 + 1;\nconst c7452 = c7451 + 1;\nconst c7453 = c7452 + 1;\nconst c7454 = c7453 + 1;\nconst c7455 = c7454 + 1;\nconst c7456 = c7455 + 1;\nconst c7457 = c7456 + 1;\nconst c7458 = c7457 + 1;\nconst c7459 = c7458 + 1;\nconst c7460 = c7459 + 1;\nconst c7461 = c7460 + 1;\nconst c7462 = c7461 + 1;\nconst c7463 = c7462 + 1;\nconst c7464 = c7463 + 1;\nconst c7465 = c7464 + 1;\nconst c7466 = c7465 + 1;\nconst c7467 = c7466 + 1;\nconst c7468 = c7467 + 1;\nconst c7469 = c7468 + 1;\nconst c7470 = c7469 + 1;\nconst c7471 = c7470 + 1;\nconst c7472 = c7471 + 1;\nconst c7473 = c7472 + 1;\nconst c7474 = c7473 + 1;\nconst c7475 = c7474 + 1;\nconst c7476 = c7475 + 1;\nconst c7477 = c7476 + 1;\nconst c7478 = c7477 + 1;\nconst c7479 = c7478 + 1;\nconst c7480 = c7479 + 1;\nconst c7481 = c7480 + 1;\nconst c7482 = c7481 + 1;\nconst c7483 = c7482 + 1;\nconst c7484 = c7483 + 1;\nconst c7485 = c7484 + 1;\nconst c7486 = c7485 + 1;\nconst c7487 = c7486 + 1;\nconst c7488 = c7487 + 1;\nconst c7489 = c7488 + 1;\nconst c7490 = c7489 + 1;\nconst c7491 = c7490 + 1;\nconst c7492 = c7491 + 1;\nconst c7493 = c7492 + 1;\nconst c7494 = c7493 + 1;\nconst c7495 = c7494 + 1;\nconst c7496 = c7495 + 1;\nconst c7497 = c7496 + 1;\nconst c7498 = c7497 + 1;\nconst c7499 = c7498 + 1;\nconst c7500 = c7499 + 1;\nconst c7501 = c7500 + 1;\nconst c7502 = c7501 + 1;\nconst c7503 = c7502 + 1;\nconst c7504 = c7503 + 1;\nconst c7505 = c7504 + 1;\nconst c7506 = c7505 + 1;\nconst c7507 = c7506 + 1;\nconst c7508 = c7507 + 1;\nconst c7509 = c7508 + 1;\nconst c7510 = c7509 + 1;\nconst c7511 = c7510 + 1;\nconst c7512 = c7511 + 1;\nconst c7513 = c7512 + 1;\nconst c7514 = c7513 + 1;\nconst c7515 = c7514 + 1;\nconst c7516 = c7515 + 1;\nconst c7517 = c7516 + 1;\nconst c7518 = c7517 + 1;\nconst c7519 = c7518 + 1;\nconst c7520 = c7519 + 1;\nconst c7521 = c7520 + 1;\nconst c7522 = c7521 + 1;\nconst c7523 = c7522 + 1;\nconst c7524 = c7523 + 1;\nconst c7525 = c7524 + 1;\nconst c7526 = c7525 + 1;\nconst c7527 = c7526 + 1;\nconst c7528 = c7527 + 1;\nconst c7529 = c7528 + 1;\nconst c7530 = c7529 + 1;\nconst c7531 = c7530 + 1;\nconst c7532 = c7531 + 1;\nconst c7533 = c7532 + 1;\nconst c7534 = c7533 + 1;\nconst c7535 = c7534 + 1;\nconst c7536 = c7535 + 1;\nconst c7537 = c7536 + 1;\nconst c7538 = c7537 + 1;\nconst c7539 = c7538 + 1;\nconst c7540 = c7539 + 1;\nconst c7541 = c7540 + 1;\nconst c7542 = c7541 + 1;\nconst c7543 = c7542 + 1;\nconst c7544 = c7543 + 1;\nconst c7545 = c7544 + 1;\nconst c7546 = c7545 + 1;\nconst c7547 = c7546 + 1;\nconst c7548 = c7547 + 1;\nconst c7549 = c7548 + 1;\nconst c7550 = c7549 + 1;\nconst c7551 = c7550 + 1;\nconst c7552 = c7551 + 1;\nconst c7553 = c7552 + 1;\nconst c7554 = c7553 + 1;\nconst c7555 = c7554 + 1;\nconst c7556 = c7555 + 1;\nconst c7557 = c7556 + 1;\nconst c7558 = c7557 + 1;\nconst c7559 = c7558 + 1;\nconst c7560 = c7559 + 1;\nconst c7561 = c7560 + 1;\nconst c7562 = c7561 + 1;\nconst c7563 = c7562 + 1;\nconst c7564 = c7563 + 1;\nconst c7565 = c7564 + 1;\nconst c7566 = c7565 + 1;\nconst c7567 = c7566 + 1;\nconst c7568 = c7567 + 1;\nconst c7569 = c7568 + 1;\nconst c7570 = c7569 + 1;\nconst c7571 = c7570 + 1;\nconst c7572 = c7571 + 1;\nconst c7573 = c7572 + 1;\nconst c7574 = c7573 + 1;\nconst c7575 = c7574 + 1;\nconst c7576 = c7575 + 1;\nconst c7577 = c7576 + 1;\nconst c7578 = c7577 + 1;\nconst c7579 = c7578 + 1;\nconst c7580 = c7579 + 1;\nconst c7581 = c7580 + 1;\nconst c7582 = c7581 + 1;\nconst c7583 = c7582 + 1;\nconst c7584 = c7583 + 1;\nconst c7585 = c7584 + 1;\nconst c7586 = c7585 + 1;\nconst c7587 = c7586 + 1;\nconst c7588 = c7587 + 1;\nconst c7589 = c7588 + 1;\nconst c7590 = c7589 + 1;\nconst c7591 = c7590 + 1;\nconst c7592 = c7591 + 1;\nconst c7593 = c7592 + 1;\nconst c7594 = c7593 + 1;\nconst c7595 = c7594 + 1;\nconst c7596 = c7595 + 1;\nconst c7597 = c7596 + 1;\nconst c7598 = c7597 + 1;\nconst c7599 = c7598 + 1;\nconst c7600 = c7599 + 1;\nconst c7601 = c7600 + 1;\nconst c7602 = c7601 + 1;\nconst c7603 = c7602 + 1;\nconst c7604 = c7603 + 1;\nconst c7605 = c7604 + 1;\nconst c7606 = c7605 + 1;\nconst c7607 = c7606 + 1;\nconst c7608 = c7607 + 1;\nconst c7609 = c7608 + 1;\nconst c7610 = c7609 + 1;\nconst c7611 = c7610 + 1;\nconst c7612 = c7611 + 1;\nconst c7613 = c7612 + 1;\nconst c7614 = c7613 + 1;\nconst c7615 = c7614 + 1;\nconst c7616 = c7615 + 1;\nconst c7617 = c7616 + 1;\nconst c7618 = c7617 + 1;\nconst c7619 = c7618 + 1;\nconst c7620 = c7619 + 1;\nconst c7621 = c7620 + 1;\nconst c7622 = c7621 + 1;\nconst c7623 = c7622 + 1;\nconst c7624 = c7623 + 1;\nconst c7625 = c7624 + 1;\nconst c7626 = c7625 + 1;\nconst c7627 = c7626 + 1;\nconst c7628 = c7627 + 1;\nconst c7629 = c7628 + 1;\nconst c7630 = c7629 + 1;\nconst c7631 = c7630 + 1;\nconst c7632 = c7631 + 1;\nconst c7633 = c7632 + 1;\nconst c7634 = c7633 + 1;\nconst c7635 = c7634 + 1;\nconst c7636 = c7635 + 1;\nconst c7637 = c7636 + 1;\nconst c7638 = c7637 + 1;\nconst c7639 = c7638 + 1;\nconst c7640 = c7639 + 1;\nconst c7641 = c7640 + 1;\nconst c7642 = c7641 + 1;\nconst c7643 = c7642 + 1;\nconst c7644 = c7643 + 1;\nconst c7645 = c7644 + 1;\nconst c7646 = c7645 + 1;\nconst c7647 = c7646 + 1;\nconst c7648 = c7647 + 1;\nconst c7649 = c7648 + 1;\nconst c7650 = c7649 + 1;\nconst c7651 = c7650 + 1;\nconst c7652 = c7651 + 1;\nconst c7653 = c7652 + 1;\nconst c7654 = c7653 + 1;\nconst c7655 = c7654 + 1;\nconst c7656 = c7655 + 1;\nconst c7657 = c7656 + 1;\nconst c7658 = c7657 + 1;\nconst c7659 = c7658 + 1;\nconst c7660 = c7659 + 1;\nconst c7661 = c7660 + 1;\nconst c7662 = c7661 + 1;\nconst c7663 = c7662 + 1;\nconst c7664 = c7663 + 1;\nconst c7665 = c7664 + 1;\nconst c7666 = c7665 + 1;\nconst c7667 = c7666 + 1;\nconst c7668 = c7667 + 1;\nconst c7669 = c7668 + 1;\nconst c7670 = c7669 + 1;\nconst c7671 = c7670 + 1;\nconst c7672 = c7671 + 1;\nconst c7673 = c7672 + 1;\nconst c7674 = c7673 + 1;\nconst c7675 = c7674 + 1;\nconst c7676 = c7675 + 1;\nconst c7677 = c7676 + 1;\nconst c7678 = c7677 + 1;\nconst c7679 = c7678 + 1;\nconst c7680 = c7679 + 1;\nconst c7681 = c7680 + 1;\nconst c7682 = c7681 + 1;\nconst c7683 = c7682 + 1;\nconst c7684 = c7683 + 1;\nconst c7685 = c7684 + 1;\nconst c7686 = c7685 + 1;\nconst c7687 = c7686 + 1;\nconst c7688 = c7687 + 1;\nconst c7689 = c7688 + 1;\nconst c7690 = c7689 + 1;\nconst c7691 = c7690 + 1;\nconst c7692 = c7691 + 1;\nconst c7693 = c7692 + 1;\nconst c7694 = c7693 + 1;\nconst c7695 = c7694 + 1;\nconst c7696 = c7695 + 1;\nconst c7697 = c7696 + 1;\nconst c7698 = c7697 + 1;\nconst c7699 = c7698 + 1;\nconst c7700 = c7699 + 1;\nconst c7701 = c7700 + 1;\nconst c7702 = c7701 + 1;\nconst c7703 = c7702 + 1;\nconst c7704 = c7703 + 1;\nconst c7705 = c7704 + 1;\nconst c7706 = c7705 + 1;\nconst c7707 = c7706 + 1;\nconst c7708 = c7707 + 1;\nconst c7709 = c7708 + 1;\nconst c7710 = c7709 + 1;\nconst c7711 = c7710 + 1;\nconst c7712 = c7711 + 1;\nconst c7713 = c7712 + 1;\nconst c7714 = c7713 + 1;\nconst c7715 = c7714 + 1;\nconst c7716 = c7715 + 1;\nconst c7717 = c7716 + 1;\nconst c7718 = c7717 + 1;\nconst c7719 = c7718 + 1;\nconst c7720 = c7719 + 1;\nconst c7721 = c7720 + 1;\nconst c7722 = c7721 + 1;\nconst c7723 = c7722 + 1;\nconst c7724 = c7723 + 1;\nconst c7725 = c7724 + 1;\nconst c7726 = c7725 + 1;\nconst c7727 = c7726 + 1;\nconst c7728 = c7727 + 1;\nconst c7729 = c7728 + 1;\nconst c7730 = c7729 + 1;\nconst c7731 = c7730 + 1;\nconst c7732 = c7731 + 1;\nconst c7733 = c7732 + 1;\nconst c7734 = c7733 + 1;\nconst c7735 = c7734 + 1;\nconst c7736 = c7735 + 1;\nconst c7737 = c7736 + 1;\nconst c7738 = c7737 + 1;\nconst c7739 = c7738 + 1;\nconst c7740 = c7739 + 1;\nconst c7741 = c7740 + 1;\nconst c7742 = c7741 + 1;\nconst c7743 = c7742 + 1;\nconst c7744 = c7743 + 1;\nconst c7745 = c7744 + 1;\nconst c7746 = c7745 + 1;\nconst c7747 = c7746 + 1;\nconst c7748 = c7747 + 1;\nconst c7749 = c7748 + 1;\nconst c7750 = c7749 + 1;\nconst c7751 = c7750 + 1;\nconst c7752 = c7751 + 1;\nconst c7753 = c7752 + 1;\nconst c7754 = c7753 + 1;\nconst c7755 = c7754 + 1;\nconst c7756 = c7755 + 1;\nconst c7757 = c7756 + 1;\nconst c7758 = c7757 + 1;\nconst c7759 = c7758 + 1;\nconst c7760 = c7759 + 1;\nconst c7761 = c7760 + 1;\nconst c7762 = c7761 + 1;\nconst c7763 = c7762 + 1;\nconst c7764 = c7763 + 1;\nconst c7765 = c7764 + 1;\nconst c7766 = c7765 + 1;\nconst c7767 = c7766 + 1;\nconst c7768 = c7767 + 1;\nconst c7769 = c7768 + 1;\nconst c7770 = c7769 + 1;\nconst c7771 = c7770 + 1;\nconst c7772 = c7771 + 1;\nconst c7773 = c7772 + 1;\nconst c7774 = c7773 + 1;\nconst c7775 = c7774 + 1;\nconst c7776 = c7775 + 1;\nconst c7777 = c7776 + 1;\nconst c7778 = c7777 + 1;\nconst c7779 = c7778 + 1;\nconst c7780 = c7779 + 1;\nconst c7781 = c7780 + 1;\nconst c7782 = c7781 + 1;\nconst c7783 = c7782 + 1;\nconst c7784 = c7783 + 1;\nconst c7785 = c7784 + 1;\nconst c7786 = c7785 + 1;\nconst c7787 = c7786 + 1;\nconst c7788 = c7787 + 1;\nconst c7789 = c7788 + 1;\nconst c7790 = c7789 + 1;\nconst c7791 = c7790 + 1;\nconst c7792 = c7791 + 1;\nconst c7793 = c7792 + 1;\nconst c7794 = c7793 + 1;\nconst c7795 = c7794 + 1;\nconst c7796 = c7795 + 1;\nconst c7797 = c7796 + 1;\nconst c7798 = c7797 + 1;\nconst c7799 = c7798 + 1;\nconst c7800 = c7799 + 1;\nconst c7801 = c7800 + 1;\nconst c7802 = c7801 + 1;\nconst c7803 = c7802 + 1;\nconst c7804 = c7803 + 1;\nconst c7805 = c7804 + 1;\nconst c7806 = c7805 + 1;\nconst c7807 = c7806 + 1;\nconst c7808 = c7807 + 1;\nconst c7809 = c7808 + 1;\nconst c7810 = c7809 + 1;\nconst c7811 = c7810 + 1;\nconst c7812 = c7811 + 1;\nconst c7813 = c7812 + 1;\nconst c7814 = c7813 + 1;\nconst c7815 = c7814 + 1;\nconst c7816 = c7815 + 1;\nconst c7817 = c7816 + 1;\nconst c7818 = c7817 + 1;\nconst c7819 = c7818 + 1;\nconst c7820 = c7819 + 1;\nconst c7821 = c7820 + 1;\nconst c7822 = c7821 + 1;\nconst c7823 = c7822 + 1;\nconst c7824 = c7823 + 1;\nconst c7825 = c7824 + 1;\nconst c7826 = c7825 + 1;\nconst c7827 = c7826 + 1;\nconst c7828 = c7827 + 1;\nconst c7829 = c7828 + 1;\nconst c7830 = c7829 + 1;\nconst c7831 = c7830 + 1;\nconst c7832 = c7831 + 1;\nconst c7833 = c7832 + 1;\nconst c7834 = c7833 + 1;\nconst c7835 = c7834 + 1;\nconst c7836 = c7835 + 1;\nconst c7837 = c7836 + 1;\nconst c7838 = c7837 + 1;\nconst c7839 = c7838 + 1;\nconst c7840 = c7839 + 1;\nconst c7841 = c7840 + 1;\nconst c7842 = c7841 + 1;\nconst c7843 = c7842 + 1;\nconst c7844 = c7843 + 1;\nconst c7845 = c7844 + 1;\nconst c7846 = c7845 + 1;\nconst c7847 = c7846 + 1;\nconst c7848 = c7847 + 1;\nconst c7849 = c7848 + 1;\nconst c7850 = c7849 + 1;\nconst c7851 = c7850 + 1;\nconst c7852 = c7851 + 1;\nconst c7853 = c7852 + 1;\nconst c7854 = c7853 + 1;\nconst c7855 = c7854 + 1;\nconst c7856 = c7855 + 1;\nconst c7857 = c7856 + 1;\nconst c7858 = c7857 + 1;\nconst c7859 = c7858 + 1;\nconst c7860 = c7859 + 1;\nconst c7861 = c7860 + 1;\nconst c7862 = c7861 + 1;\nconst c7863 = c7862 + 1;\nconst c7864 = c7863 + 1;\nconst c7865 = c7864 + 1;\nconst c7866 = c7865 + 1;\nconst c7867 = c7866 + 1;\nconst c7868 = c7867 + 1;\nconst c7869 = c7868 + 1;\nconst c7870 = c7869 + 1;\nconst c7871 = c7870 + 1;\nconst c7872 = c7871 + 1;\nconst c7873 = c7872 + 1;\nconst c7874 = c7873 + 1;\nconst c7875 = c7874 + 1;\nconst c7876 = c7875 + 1;\nconst c7877 = c7876 + 1;\nconst c7878 = c7877 + 1;\nconst c7879 = c7878 + 1;\nconst c7880 = c7879 + 1;\nconst c7881 = c7880 + 1;\nconst c7882 = c7881 + 1;\nconst c7883 = c7882 + 1;\nconst c7884 = c7883 + 1;\nconst c7885 = c7884 + 1;\nconst c7886 = c7885 + 1;\nconst c7887 = c7886 + 1;\nconst c7888 = c7887 + 1;\nconst c7889 = c7888 + 1;\nconst c7890 = c7889 + 1;\nconst c7891 = c7890 + 1;\nconst c7892 = c7891 + 1;\nconst c7893 = c7892 + 1;\nconst c7894 = c7893 + 1;\nconst c7895 = c7894 + 1;\nconst c7896 = c7895 + 1;\nconst c7897 = c7896 + 1;\nconst c7898 = c7897 + 1;\nconst c7899 = c7898 + 1;\nconst c7900 = c7899 + 1;\nconst c7901 = c7900 + 1;\nconst c7902 = c7901 + 1;\nconst c7903 = c7902 + 1;\nconst c7904 = c7903 + 1;\nconst c7905 = c7904 + 1;\nconst c7906 = c7905 + 1;\nconst c7907 = c7906 + 1;\nconst c7908 = c7907 + 1;\nconst c7909 = c7908 + 1;\nconst c7910 = c7909 + 1;\nconst c7911 = c7910 + 1;\nconst c7912 = c7911 + 1;\nconst c7913 = c7912 + 1;\nconst c7914 = c7913 + 1;\nconst c7915 = c7914 + 1;\nconst c7916 = c7915 + 1;\nconst c7917 = c7916 + 1;\nconst c7918 = c7917 + 1;\nconst c7919 = c7918 + 1;\nconst c7920 = c7919 + 1;\nconst c7921 = c7920 + 1;\nconst c7922 = c7921 + 1;\nconst c7923 = c7922 + 1;\nconst c7924 = c7923 + 1;\nconst c7925 = c7924 + 1;\nconst c7926 = c7925 + 1;\nconst c7927 = c7926 + 1;\nconst c7928 = c7927 + 1;\nconst c7929 = c7928 + 1;\nconst c7930 = c7929 + 1;\nconst c7931 = c7930 + 1;\nconst c7932 = c7931 + 1;\nconst c7933 = c7932 + 1;\nconst c7934 = c7933 + 1;\nconst c7935 = c7934 + 1;\nconst c7936 = c7935 + 1;\nconst c7937 = c7936 + 1;\nconst c7938 = c7937 + 1;\nconst c7939 = c7938 + 1;\nconst c7940 = c7939 + 1;\nconst c7941 = c7940 + 1;\nconst c7942 = c7941 + 1;\nconst c7943 = c7942 + 1;\nconst c7944 = c7943 + 1;\nconst c7945 = c7944 + 1;\nconst c7946 = c7945 + 1;\nconst c7947 = c7946 + 1;\nconst c7948 = c7947 + 1;\nconst c7949 = c7948 + 1;\nconst c7950 = c7949 + 1;\nconst c7951 = c7950 + 1;\nconst c7952 = c7951 + 1;\nconst c7953 = c7952 + 1;\nconst c7954 = c7953 + 1;\nconst c7955 = c7954 + 1;\nconst c7956 = c7955 + 1;\nconst c7957 = c7956 + 1;\nconst c7958 = c7957 + 1;\nconst c7959 = c7958 + 1;\nconst c7960 = c7959 + 1;\nconst c7961 = c7960 + 1;\nconst c7962 = c7961 + 1;\nconst c7963 = c7962 + 1;\nconst c7964 = c7963 + 1;\nconst c7965 = c7964 + 1;\nconst c7966 = c7965 + 1;\nconst c7967 = c7966 + 1;\nconst c7968 = c7967 + 1;\nconst c7969 = c7968 + 1;\nconst c7970 = c7969 + 1;\nconst c7971 = c7970 + 1;\nconst c7972 = c7971 + 1;\nconst c7973 = c7972 + 1;\nconst c7974 = c7973 + 1;\nconst c7975 = c7974 + 1;\nconst c7976 = c7975 + 1;\nconst c7977 = c7976 + 1;\nconst c7978 = c7977 + 1;\nconst c7979 = c7978 + 1;\nconst c7980 = c7979 + 1;\nconst c7981 = c7980 + 1;\nconst c7982 = c7981 + 1;\nconst c7983 = c7982 + 1;\nconst c7984 = c7983 + 1;\nconst c7985 = c7984 + 1;\nconst c7986 = c7985 + 1;\nconst c7987 = c7986 + 1;\nconst c7988 = c7987 + 1;\nconst c7989 = c7988 + 1;\nconst c7990 = c7989 + 1;\nconst c7991 = c7990 + 1;\nconst c7992 = c7991 + 1;\nconst c7993 = c7992 + 1;\nconst c7994 = c7993 + 1;\nconst c7995 = c7994 + 1;\nconst c7996 = c7995 + 1;\nconst c7997 = c7996 + 1;\nconst c7998 = c7997 + 1;\nconst c7999 = c7998 + 1;\nconst c8000 = c7999 + 1;\nenum E { A = c8000 }\nconst ok: E.A = 8001;\nconst bad: E.A = 8002;\nexport { ok, bad };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "72-R04a": { + "files": { + "a.ts": "import { make } from \"dep\";\ndeclare module \"foo\" { interface C { added: number } }\nmake().own;\nmake().added;\nconst sentinel: number = \"\";\n", + "node_modules/@types/foo/index.d.ts": "export declare class C { own: number; }\n", + "node_modules/@types/foo/package.json": "{ \"name\": \"@types/foo\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/dep/index.d.ts": "import { C } from \"foo\";\nexport declare function make(): C;\n", + "node_modules/dep/node_modules/@types/foo/index.d.ts": "export declare class C { own: number; }\n", + "node_modules/dep/node_modules/@types/foo/package.json": "{ \"name\": \"@types/foo\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/dep/package.json": "{ \"name\": \"dep\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"types\": [\"foo\"], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\"}}" + } + }, + "72-R04b": { + "files": { + "a.ts": "import { C } from \"./node_modules/old\";\nimport { take } from \"dep\";\ntake(new C());\ndeclare module \"old\" { interface X { x: 1 } }\nconst sentinel: number = \"\";\n", + "node_modules/dep/index.d.ts": "import { C } from \"old\";\nexport declare function take(c: C): void;\n", + "node_modules/dep/node_modules/old/index.d.ts": "export declare class C { private p; }\n", + "node_modules/dep/node_modules/old/package.json": "{ \"name\": \"old\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/dep/package.json": "{ \"name\": \"dep\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/old/index.d.ts": "export declare class C { private p; }\n", + "node_modules/old/package.json": "{ \"name\": \"old\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\"}}" + } + }, + "72-R04c": { + "files": { + "a.ts": "import { C } from \"old\";\nimport { take } from \"dep\";\ntake(new C());\nconst sentinel: number = \"\";\n", + "node_modules/dep/index.d.ts": "import { C } from \"old\";\nexport declare function take(c: C): void;\n", + "node_modules/dep/node_modules/old/index.d.ts": "export declare class C { private p; }\n", + "node_modules/dep/node_modules/old/package.json": "{ \"name\": \"old\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/dep/package.json": "{ \"name\": \"dep\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/old/index.d.ts": "export declare class C { private p; }\n", + "node_modules/old/package.json": "{ \"name\": \"old\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"noResolve\": true}, \"files\": [\"a.ts\", \"node_modules/old/index.d.ts\", \"node_modules/dep/index.d.ts\", \"node_modules/dep/node_modules/old/index.d.ts\"]}" + } + }, + "72-R04d": { + "files": { + "a.ts": "import { T } from \"./node_modules/third\";\nimport \"old\";\nimport \"dep\";\nimport { take3 } from \"dep3\";\ntake3(new T());\nconst sentinel: number = \"\";\n", + "node_modules/dep/index.d.ts": "import \"old\";\nexport {};\n", + "node_modules/dep/node_modules/old/index.d.ts": "import \"third\";\nexport declare class C { private p; }\n", + "node_modules/dep/node_modules/old/package.json": "{ \"name\": \"old\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/dep/package.json": "{ \"name\": \"dep\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/dep3/index.d.ts": "import { T } from \"third\";\nexport declare function take3(t: T): void;\n", + "node_modules/dep3/node_modules/third/index.d.ts": "export declare class T { private t; }\n", + "node_modules/dep3/node_modules/third/package.json": "{ \"name\": \"third\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/dep3/package.json": "{ \"name\": \"dep3\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/old/index.d.ts": "export declare class C { private p; }\n", + "node_modules/old/package.json": "{ \"name\": \"old\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "node_modules/third/index.d.ts": "export declare class T { private t; }\n", + "node_modules/third/package.json": "{ \"name\": \"third\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\"}}" + } + }, + "72-R10a": { + "files": { + "a.ts": "type Primitive = string | number | boolean | null | undefined;\ntype DeepReadonly = T extends Primitive ? T : { readonly [K in keyof T]: DeepReadonly };\nclass Store { snapshot!: S }\nclass App extends Store> { count = 1 }\nclass Other extends Store> { count = 1 }\nnew App().snapshot.count = 2;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "72-R10b": { + "files": { + "a.ts": "type Cond = T extends string | number ? { y: 1 } : { z: 1 };\ndeclare const ctor: new () => Cond;\nclass C7 extends ctor { x = 1 }\nnew C7().z;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "72-R10c": { + "files": { + "a.ts": "type Cond = T extends string | number ? { y: 1 } : { z: 1 };\nclass Base { b!: T }\ndeclare const pre: C1; pre.x;\nclass C1 extends Base> { x = 1 }\nfunction early(c: C2) { return c.x; }\nclass C2 extends Base> { x = 1 }\nlet t3: Cond;\nclass C3 extends Base> { x = 1 }\nlet t4: C4 | undefined;\nclass C4 extends Base> { x = 1 }\nlet t5 = (c: C5): string | number => c;\nclass C5 extends Base> { x = 1 }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "72-R10d": { + "files": { + "a.ts": "class Base { b!: T }\ntype P1 = T extends string ? 1 : 2;\ntype P2 = T extends string | number ? 1 : 2;\ntype P3 = T extends null | undefined ? 1 : 2;\ntype P4 = T extends object ? 1 : 2;\ntype P5 = T extends Function ? 1 : 2;\ntype P6 = T extends any[] ? 1 : 2;\ntype P7 = T extends string | any[] ? 1 : 2;\ntype P8 = T extends \"a\" | \"b\" ? 1 : 2;\ntype P9 = T extends boolean ? 1 : 2;\ntype P10 = T extends string | object ? 1 : 2;\ntype P11 = T extends unknown ? 1 : 2;\ntype P12 = T extends never ? 1 : 2;\ntype P13 = T extends {} ? 1 : 2;\ntype P14 = [T] extends [string | number] ? 1 : 2;\ntype P15 = T extends string & { brand: 1 } ? 1 : 2;\ntype P16 = T extends `a${string}` | number ? 1 : 2;\ntype P17 = T extends keyof any ? 1 : 2;\ntype P18 = string | number extends T ? 1 : 2;\ntype P19 = T extends bigint | symbol ? T : { readonly [K in keyof T]: P19 };\nclass D1 extends Base> { x = 1 }\nclass D2 extends Base> { x = 1 }\nclass D3 extends Base> { x = 1 }\nclass D4 extends Base> { x = 1 }\nclass D5 extends Base> { x = 1 }\nclass D6 extends Base> { x = 1 }\nclass D7 extends Base> { x = 1 }\nclass D8 extends Base> { x = 1 }\nclass D9 extends Base> { x = 1 }\nclass D10 extends Base> { x = 1 }\nclass D11 extends Base> { x = 1 }\nclass D12 extends Base> { x = 1 }\nclass D13 extends Base> { x = 1 }\nclass D14 extends Base> { x = 1 }\nclass D15 extends Base> { x = 1 }\nclass D16 extends Base> { x = 1 }\nclass D17 extends Base> { x = 1 }\nclass D18 extends Base> { x = 1 }\nclass D19 extends Base> { x = 1 }\nclass D20 extends Base { x = 1 }\nclass D21 extends Base> { x = 1 }\nclass D22 extends Base> { x = 1 }\nclass D23 extends Base> { x = 1 }\nclass D24 extends Base> { x = 1 }\nnamespace NS { export class B { b!: T } }\nclass D25 extends NS.B> { x = 1 }\nclass D26 extends (Base)> { x = 1 }\nclass D27 extends Base> {}\nclass D28 extends Base> { static s = 1 }\nabstract class D29 extends Base> { abstract x: number }\nconst D30 = class D30i extends Base> { x = 1 };\nclass D31 extends Base>> { x!: T }\nclass D32 extends Base>> { x = 1 }\nclass D33 extends Base<{ p: P2 }> { x = 1 }\nclass D34 extends Base<[P2]> { x = 1 }\nclass D35 extends Base<() => P2> { x = 1 }\nclass D36 extends Base> { x = 1 } class D37 extends Base> { y = 1 }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "72-R14": { + "files": { + "a.ts": "declare function id(x: T): T;\ntype R = (x: number) => string;\nconst objv = { z: 1, cb: (): R => null! };\nconst { z, ...rest1 } = objv; declare function h1(a: T, o: typeof rest1): T; h1(1, { cb: () => id });\nconst sp1 = { ...objv }; declare function h2(a: T, o: typeof sp1): T; h2(1, { z: 1, cb: () => id });\nconst sp2 = { ...objv, k: 1 }; declare function h3(a: T, o: typeof sp2): T; h3(1, { z: 1, k: 1, cb: () => id });\nlet wid = { cb: (): R => null!, n: null }; declare function h4(a: T, o: typeof wid): T; h4(1, { n: null, cb: () => id });\nconst asg = Object.assign({ q: 1 }, objv); declare function h5(a: T, o: typeof asg): T; h5(1, { q: 1, z: 1, cb: () => id });\nconst cex = class { cb!: () => R }; declare function h6(a: T, o: InstanceType): T; h6(1, { cb: () => id });\nenum E { A } namespace E { export const cb: () => R = null! } declare function h7(a: T, o: typeof E): T; h7(1, { A: E.A, cb: () => id });\nnamespace V { export const cb: () => R = null! } declare function h8(a: T, o: typeof V): T; h8(1, { cb: () => id });\nfunction FN() {} namespace FN { export const cb: () => R = null! } declare function h9(a: T, o: Pick): T; h9(1, { cb: () => id });\nfunction withRest({ z, ...r }: typeof objv) { function h(a: T, o: typeof r): T { return a } h(1, { cb: () => id }); }\nconst [, ...arest] = [1, (): R => null!] as [number, () => R]; declare function h10(a: T, o: typeof arest): T; h10(1, [() => id]);\ndeclare const u: { z: 1; cb: () => R } | { z: 2; cb: () => R; w: 1 }; const { z: z2, ...rest2 } = u; declare function h11(a: T, o: typeof rest2): T; h11(1, { cb: () => id });\nconst { ...rest3 } = objv; declare function h12(a: T, o: typeof rest3): T; h12(1, { z: 1, cb: () => id });\ntype RestAlias = typeof rest1; declare function h13(a: T, o: RestAlias): T; h13(1, { cb: () => id });\ndeclare function h14(a: T, o: (typeof rest1)[]): T; h14(1, [{ cb: () => id }]);\ndeclare function h15(a: T, o: typeof rest1 | undefined): T; h15(1, { cb: () => id });\ndeclare function h16(a: T, o: (typeof rest1)[\"cb\"]): T; h16(1, () => id);\nlet r5; ({ z: r5, ...r5 } = objv);\nconst nested = { in: rest1 }; declare function h17(a: T, o: typeof nested): T; h17(1, { in: { cb: () => id } });\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "72-R15a": { + "files": { + "a.ts": "function f1(a: string, b?: ReturnType): string;\nfunction f1(a: number, b?: number): number;\nfunction f1(a: any, b?: any) { return a; }\nfunction g1() { return f1(1, 2); }\nfunction g2() { return f2(1, 2); }\nfunction f2(a: string, b?: ReturnType): string;\nfunction f2(a: number, b?: number): number;\nfunction f2(a: any, b?: any) { return a; }\ndeclare function f3(a: string, b?: typeof v3): string;\ndeclare function f3(a: number, b?: number): number;\nconst v3 = [f3(1, 2)];\nclass C4 {\n m(a: string, b?: ReturnType): string;\n m(a: number, b?: number): number;\n m(a: any, b?: any) { return a; }\n n() { return [this.m(1, 2)]; }\n}\ninterface I5 { (a: string, b?: typeof v5): string; (a: number, b?: number): number }\ndeclare const i5: I5;\nconst v5 = [i5(1, 2)];\ndeclare class C6 { constructor(a: string, b?: typeof v6); constructor(a: number, b?: number); }\nconst v6 = [new C6(1, 2)];\ndeclare function f7(a: string, ...b: (typeof v7)[]): string;\ndeclare function f7(a: number, ...b: number[]): number;\nconst v7 = [f7(1, 2)];\ndeclare function f8(a: string, b: typeof v8, c?: 1): string;\ndeclare function f8(a: number, b: number, c?: 1): number;\nconst v8 = [f8(1, 2, 1)];\ndeclare function f9(a: string, b?: typeof v9, c?: T): string;\ndeclare function f9(a: number, b?: number): number;\nconst v9 = [f9(1, 2)];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "72-R15b": { + "files": { + "a.ts": "function f1(a: number, b = g1()) { return a; }\nfunction g1() { return f1(\"wrong\", 1); }\nfunction g2() { return f2(\"wrong\", 1); }\nfunction f2(a: number, b = g2()) { return a; }\nfunction f3(a: number, b = g3()) { return a; }\nfunction g3() { return f3(1, 1); }\nfunction f4(a: number, b = g4()) { return a; }\nfunction g4() { return [f4(\"wrong\", [])]; }\nfunction f5(a: number, b = g5()) { return a; }\nfunction g5() { return { r: f5(\"wrong\") }; }\nfunction f6(a: number, b = g6()) { return a; }\nfunction g6() { return { r: f6(1) }; }\nfunction f7(a: number, b: ReturnType) { return a; }\nfunction g7() { return { r: f7(\"wrong\", null!) }; }\nfunction f8(a: number, b: ReturnType) { return a; }\nfunction g8() { return { r: f8(1, null!) }; }\nfunction f9(a: number, b = g9().r) { return [a]; }\nfunction g9() { return { r: f9(\"wrong\", []) }; }\nclass C10 { m(a: number, b = this.n()) { return [a]; } n() { return { r: this.m(\"wrong\", null!) }; } }\nclass C11 { m(a: number, b = this.n()) { return [a]; } n() { return { r: this.m(1, null!) }; } }\nclass C12 { p = this.m(\"wrong\", null!); m(a: number, b = this.p) { return [a]; } }\nclass C13 { p = this.m(1, null!); m(a: number, b = this.p) { return [a]; } }\nconst o14 = { m(a: number, b = o14.n()) { return [a]; }, n() { return { r: o14.m(\"wrong\", null!) }; } };\nfunction f15(a: number, b = g15(), c = 1) { return [a]; }\nfunction g15() { return { r: f15(\"wrong\", null!, \"also wrong\") }; }\nfunction f16(a: number, b: string, c = g16()) { return [a]; }\nfunction g16() { return { r: f16(1, 2, null!) }; }\nfunction f17(a: number, b: string, c = g17()) { return [a]; }\nfunction g17() { return { r: f17(1, \"\", null!) }; }\nfunction f18(cb: (x: number) => void, b = g18()) { return [cb]; }\nfunction g18() { return { r: f18((x: string) => {}, null!) }; }\nfunction f19(cb: (x: number) => void, b = g19()) { return [cb]; }\nfunction g19() { return { r: f19(x => { x.nope }, null!) }; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "72-R19": { + "files": { + "a.ts": "declare function pair
(f: new (...a: A) => R, g: new (...b: B) => S): (a: A, b: B) => [R, S];\ndeclare function pairF(f: (...a: A) => R, g: (...b: B) => S): (a: A, b: B) => [R, S];\ndeclare function f1(t: T): T;\ndeclare function f2(t: T, u: U): [T, U];\ndeclare function f3(t: T, u: U): [T, U];\ndeclare function f4(t: T, u: U): [T, U];\ndeclare function f5(t: T, k: K): T[K];\ndeclare class C1 { constructor(t: T) }\ndeclare class C2 { constructor(t: T, u: U) }\ndeclare class C3 { constructor(t: T, u: U) }\ndeclare class C4 { constructor(t: T, u: U) }\ndeclare class C5 { constructor(t: T, k: K) }\nconst a1: 0 = pairF(f1, f2);\nconst a2: 0 = pairF(f1, f3);\nconst a3: 0 = pairF(f1, f4);\nconst a4: 0 = pairF(f1, f5);\nconst a5: 0 = pairF(f2, f1);\nconst b1: 0 = pair(C1, C2);\nconst b2: 0 = pair(C1, C3);\nconst b3: 0 = pair(C1, C4);\nconst b4: 0 = pair(C1, C5);\nconst b5: 0 = pair(C2, C1);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R01a": { + "files": { + "a.ts": "declare function c(): boolean;\nfunction minimal() {\n let y: string | number = \"\";\n while (c()) {\n if (y === 1) { }\n switch (y) { case 0: y = 0; }\n }\n}\nfunction likely(a: string[]) {\n let v: string | number = \"\";\n for (const e of a) {\n if (v === 1) { c(); }\n switch (v) {\n case 0: v = 1; break;\n case \"\": v = 0; break;\n }\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R01b": { + "files": { + "a.ts": "declare function c(): boolean;\nfunction missed() {\n let x: string | 1 | boolean = \"\";\n let y: string | number = \"\";\n while (c()) {\n x;\n if (y === 1) { }\n x = y;\n if (c()) y = 0;\n }\n}\nfunction otherText() {\n let x: string | boolean = \"\";\n let y: string | number = \"\";\n while (c()) {\n x;\n if (y === 1) { }\n x = y;\n if (c()) y = 0;\n }\n}\nfunction reportedTwice() {\n let x: string | number | boolean = \"\";\n let y: string | number = \"\";\n while (c()) {\n x;\n if (y === 1) { }\n x = (y satisfies never);\n if (c()) y = 0;\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R01c": { + "files": { + "a.ts": "declare function c(): boolean;\ntype U = string | boolean;\nfunction afterLoop(x: U) {\n if (x) { x = true; }\n while (c()) { c(); }\n const p: number = x;\n}\nfunction afterIf(x: U) {\n if (x) { x = true; }\n if (c()) { c(); }\n const p: number = x;\n}\nfunction afterTry(x: U) {\n if (x) { x = true; }\n try { c(); } catch { }\n const p: number = x;\n}\ninterface Options { verbose?: Flag }\ntype Flag = boolean | \"auto\" | undefined;\nfunction likely(o: Options, args: string[]) {\n let verbose: Flag = o.verbose;\n if (verbose === \"auto\") { verbose = false; }\n for (const a of args) { c(); }\n const n: number = verbose;\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R01d": { + "files": { + "a.ts": "declare function c(): boolean;\ndeclare function log(v: unknown): void;\nfunction likely(tokens: string[]) {\n let current: string | null = \"\";\n let result: string | number | null = null;\n let total = 0;\n for (const t of tokens) {\n if (result !== null) log(result);\n if (current) { log(current); }\n result = current ?? 0;\n if (t === \";\") current = null;\n if (typeof result === \"number\") total += result.toFixed().length;\n }\n}\nfunction minimal() {\n let x: string | null = \"\";\n let y: string | number | null = null;\n while (c()) {\n y;\n if (x) { }\n y = x ?? 0;\n if (c()) x = null;\n const p: never = y;\n }\n}\nfunction nested() {\n let x: string | null = \"\";\n let y: string | number | null = null;\n while (y == null) {\n while (typeof x === \"string\" || c()) {\n y = x ?? 0;\n }\n if (c()) x = null;\n const p: never = y;\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R01e": { + "files": { + "a.ts": "declare function fail(): never;\ndeclare function c(): boolean;\ndeclare function use(v: unknown): void;\ndeclare const arr: number[];\ntype U = string | number | boolean | null | undefined;\nfunction f4(x: string | number) { fail(); do { try { } finally { x.foo; } } while (true); }\nfunction f7(x: string | number) { fail(); do { try { } finally { try { x.foo; } finally { } } } while (true); }\nfunction plainLoop(x: string | number) { fail(); do { x.foo; } while (true); }\nfunction plainFinally(x: string | number) { fail(); try { } finally { x.foo; } }\n// the other way round: tsc reports TS2339 on `never` at the `o.x` of the switch, bun does not\nfunction f43(o: { x: U }) { fail(); do { try { } catch { try { } catch { use(o.x); } switch (typeof o.x) { } } } while (c() && o.x == null); if (typeof o.x === \"boolean\") { } }\n// `arr`, a global constant, is `never` in bun (TS2488), not in tsc\nfunction f140(o: { n: { x: U; y: U } }) { try { fail(); } finally { switch (typeof o.n.y) { case \"boolean\": do { } while (typeof o.n.x === \"boolean\"); for (const e of arr) { } } } for (const e of arr) { } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R01f": { + "files": { + "a.ts": "type U = string | number | boolean | null | undefined;\nfunction missed(o: { x: U }) { if (o[\"x\"]) { if (o[\"x\"] === 0) { o[\"x\"].toFixed(); } } }\nfunction element(o: { x: U }) { if (o[\"x\"]) { if (o[\"x\"] === 0) { const p: never = o[\"x\"]; } } }\nfunction property(o: { x: U }) { if (o.x) { if (o.x === 0) { const p: never = o.x; } } }\nfunction mixed(o: { x: U }) { if (o[\"x\"]) { if (o.x === 0) { const p: never = o[\"x\"]; const q: never = o.x; } } }\nfunction text(o: { x: U }) { if (o[\"x\"]) { if (o[\"x\"] === \"\") { const p: never = o[\"x\"]; } } }\nfunction falsy(o: { x: U }) { if (!o[\"x\"]) { if (o[\"x\"] === 1) { const p: never = o[\"x\"]; } } }\nfunction plainNumber(o: { x: number }) { if (o[\"x\"]) { if (o[\"x\"] === 0) { const p: never = o[\"x\"]; } } }\nfunction arrayIndex(o: U[]) { if (o[0]) { if (o[0] === 0) { const p: never = o[0]; } } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R03a": { + "files": { + "a.ts": "declare function c(): boolean;\nfunction call() { let x = []; for (; true; x.push(\"\")) { if (Array.isArray(x)) { if (x) break; } } }\nfunction callOfName() { let x = []; for (; true; x()) { if (Array.isArray(x)) { if (x) break; } } }\nfunction construct() { let x = []; for (; true; new x()) { if (Array.isArray(x)) { if (x) break; } } }\nfunction chain() { let x = []; for (; true; x.push(\"\").toFixed()) { if (Array.isArray(x)) { if (x) break; } } }\nfunction callback() { let x = []; for (; true; x.map(e => e)) { if (Array.isArray(x)) { if (x) break; } } }\nfunction optional() { let x = []; for (; true; x?.push(\"\")) { if (Array.isArray(x)) { if (x) break; } } }\nfunction element() { let x = []; for (; true; x[\"push\"](\"\")) { if (Array.isArray(x)) { if (x) break; } } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R03b": { + "files": { + "a.ts": "declare function c(): boolean;\ndeclare function s(): string;\nfunction valid() {\n let x = []; let y = [];\n do {\n while (c()) {\n try { x.push(y); if ((x = [])) continue; } finally { const p: never = x; y.push(x.pop()); }\n }\n y = [];\n } while (c() && y.push(1));\n}\nfunction besideImplicitAny() {\n let x = []; let y = [];\n while (c()) {\n try { x.push(...y, {}); x.push(...y); const p: never = x; } catch { if (x === y || c()) break; }\n y.push(s());\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R03c": { + "files": { + "a.ts": "declare function c(): boolean;\nfunction f() {\n let x = []; const y = [];\n while (c()) {\n do {\n if (x.length) { for (y.push(0); (x = []); ) { } }\n else { if (x === y) return; }\n } while (x.push(1));\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R04": { + "files": { + "a.ts": "import { L3 } from \"./b\";\ndeclare const u: unknown;\n// an ambient class: no TS2449\nconst k1 = u instanceof L1 ? \"s\" : \"s\";\ndeclare class L1 { static [k1]: number; i: number }\nconst p1: never = L1.s;\n// a class in another file\nexport const k3 = u instanceof L3 ? \"s\" : \"s\";\nconst p3: never = L3.s;\n// with TS2449\nconst k2 = u instanceof L2 ? \"s\" : \"s\";\nclass L2 { static [k2] = 1; i = 1 }\nconst p2: never = L2.s;\nconst sentinel: number = \"\";\n", + "b.ts": "import { k3 } from \"./a\";\nexport class L3 { static [k3] = 1; i = 1 }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R06": { + "files": { + "a.ts": "const obj = { a: 1, b: { c: 2 } };\nconst { a: _a, ...rest } = obj;\ndeclare function f1(cb: (x: T) => typeof rest): T;\nfunction g1(x: number) { return f1(g1); }\ndeclare function f2(x: { a: T, cb: () => typeof rest }): T;\nfunction g2() { return f2({ a: 1, cb: g2 }); }\nfunction h({ a, ...more }: { a: number, z: string }) {\n function f3(cb: (x: T) => typeof more): T { throw 0; }\n function g3(x: number) { return f3(g3); }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R09": { + "files": { + "a.ts": "declare function keys(o: Record): K[];\ndeclare function f2(x: { [P in K]: X }): [K, X];\nfunction strict(rw: R & W, wv: W & V, wo: W & { c: 3 }) {\n const k1: \"a\"[] = keys(rw);\n const k2: (\"a\" | \"b\")[] = keys(wv);\n const k3: (\"a\" | \"c\")[] = keys(wo);\n const p1: never = f2(rw);\n const p2: never = f2(wv);\n const p3: never = f2(wo);\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R09b": { + "files": { + "a.ts": "declare function f2(x: { [P in K]: X }): [K, X];\nfunction g(ts: T & S, tw: T & W, to: T & { b: 1 }) {\n const k1: never = f2(ts);\n const k4: never = f2(tw);\n const k5: never = f2(to);\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"strictNullChecks\": false, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R12": { + "files": { + "a.ts": "declare function t0(): T;\ndeclare function box(): { v: T };\ndeclare function prom(): Promise;\ndeclare function dflt(): T;\nlet n: number, u: unknown;\ndeclare let d: number | undefined;\ndeclare const o: { p: number };\n({ a: n } = t0());\n({ n } = t0());\n({ a: u } = t0());\n({ a: n = 1 } = t0());\n({ a: { b: n } } = t0());\n({ v: n } = box());\n({ v: { w: n } } = box());\nasync function f() { ({ a: n } = await prom()); }\n// no error in either: an array literal is a tuple (one identity), a default for every type parameter skips the test,\n// and a left side that needs flow analysis is cached by getTypeOfExpression\n[n] = t0();\n({ a: n } = dflt());\n({ a: o.p } = t0());\n({ a: n = d! } = t0());\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R13a": { + "files": { + "a.ts": "function f({ o0: { f0: n1 = () => {}, f1: n2 = () => {}, f2: n3 = () => {}, f3: n4 = () => {}, f4: n5 = () => {}, f5: n6 = () => {}, f6: n7 = () => {}, f7: n8 = () => {}, f8: n9 = () => {}, f9: n10 = () => {}, f10: n11 = () => {}, f11: n12 = () => {}, f12: n13 = () => {}, f13: n14 = () => {}, f14: n15 = () => {}, f15: n16 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o1: { f0: n17 = () => {}, f1: n18 = () => {}, f2: n19 = () => {}, f3: n20 = () => {}, f4: n21 = () => {}, f5: n22 = () => {}, f6: n23 = () => {}, f7: n24 = () => {}, f8: n25 = () => {}, f9: n26 = () => {}, f10: n27 = () => {}, f11: n28 = () => {}, f12: n29 = () => {}, f13: n30 = () => {}, f14: n31 = () => {}, f15: n32 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o2: { f0: n33 = () => {}, f1: n34 = () => {}, f2: n35 = () => {}, f3: n36 = () => {}, f4: n37 = () => {}, f5: n38 = () => {}, f6: n39 = () => {}, f7: n40 = () => {}, f8: n41 = () => {}, f9: n42 = () => {}, f10: n43 = () => {}, f11: n44 = () => {}, f12: n45 = () => {}, f13: n46 = () => {}, f14: n47 = () => {}, f15: n48 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o3: { f0: n49 = () => {}, f1: n50 = () => {}, f2: n51 = () => {}, f3: n52 = () => {}, f4: n53 = () => {}, f5: n54 = () => {}, f6: n55 = () => {}, f7: n56 = () => {}, f8: n57 = () => {}, f9: n58 = () => {}, f10: n59 = () => {}, f11: n60 = () => {}, f12: n61 = () => {}, f13: n62 = () => {}, f14: n63 = () => {}, f15: n64 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o4: { f0: n65 = () => {}, f1: n66 = () => {}, f2: n67 = () => {}, f3: n68 = () => {}, f4: n69 = () => {}, f5: n70 = () => {}, f6: n71 = () => {}, f7: n72 = () => {}, f8: n73 = () => {}, f9: n74 = () => {}, f10: n75 = () => {}, f11: n76 = () => {}, f12: n77 = () => {}, f13: n78 = () => {}, f14: n79 = () => {}, f15: n80 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o5: { f0: n81 = () => {}, f1: n82 = () => {}, f2: n83 = () => {}, f3: n84 = () => {}, f4: n85 = () => {}, f5: n86 = () => {}, f6: n87 = () => {}, f7: n88 = () => {}, f8: n89 = () => {}, f9: n90 = () => {}, f10: n91 = () => {}, f11: n92 = () => {}, f12: n93 = () => {}, f13: n94 = () => {}, f14: n95 = () => {}, f15: n96 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o6: { f0: n97 = () => {}, f1: n98 = () => {}, f2: n99 = () => {}, f3: n100 = () => {}, f4: n101 = () => {}, f5: n102 = () => {}, f6: n103 = () => {}, f7: n104 = () => {}, f8: n105 = () => {}, f9: n106 = () => {}, f10: n107 = () => {}, f11: n108 = () => {}, f12: n109 = () => {}, f13: n110 = () => {}, f14: n111 = () => {}, f15: n112 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o7: { f0: n113 = () => {}, f1: n114 = () => {}, f2: n115 = () => {}, f3: n116 = () => {}, f4: n117 = () => {}, f5: n118 = () => {}, f6: n119 = () => {}, f7: n120 = () => {}, f8: n121 = () => {}, f9: n122 = () => {}, f10: n123 = () => {}, f11: n124 = () => {}, f12: n125 = () => {}, f13: n126 = () => {}, f14: n127 = () => {}, f15: n128 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o8: { f0: n129 = () => {}, f1: n130 = () => {}, f2: n131 = () => {}, f3: n132 = () => {}, f4: n133 = () => {}, f5: n134 = () => {}, f6: n135 = () => {}, f7: n136 = () => {}, f8: n137 = () => {}, f9: n138 = () => {}, f10: n139 = () => {}, f11: n140 = () => {}, f12: n141 = () => {}, f13: n142 = () => {}, f14: n143 = () => {}, f15: n144 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o9: { f0: n145 = () => {}, f1: n146 = () => {}, f2: n147 = () => {}, f3: n148 = () => {}, f4: n149 = () => {}, f5: n150 = () => {}, f6: n151 = () => {}, f7: n152 = () => {}, f8: n153 = () => {}, f9: n154 = () => {}, f10: n155 = () => {}, f11: n156 = () => {}, f12: n157 = () => {}, f13: n158 = () => {}, f14: n159 = () => {}, f15: n160 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o10: { f0: n161 = () => {}, f1: n162 = () => {}, f2: n163 = () => {}, f3: n164 = () => {}, f4: n165 = () => {}, f5: n166 = () => {}, f6: n167 = () => {}, f7: n168 = () => {}, f8: n169 = () => {}, f9: n170 = () => {}, f10: n171 = () => {}, f11: n172 = () => {}, f12: n173 = () => {}, f13: n174 = () => {}, f14: n175 = () => {}, f15: n176 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o11: { f0: n177 = () => {}, f1: n178 = () => {}, f2: n179 = () => {}, f3: n180 = () => {}, f4: n181 = () => {}, f5: n182 = () => {}, f6: n183 = () => {}, f7: n184 = () => {}, f8: n185 = () => {}, f9: n186 = () => {}, f10: n187 = () => {}, f11: n188 = () => {}, f12: n189 = () => {}, f13: n190 = () => {}, f14: n191 = () => {}, f15: n192 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o12: { f0: n193 = () => {}, f1: n194 = () => {}, f2: n195 = () => {}, f3: n196 = () => {}, f4: n197 = () => {}, f5: n198 = () => {}, f6: n199 = () => {}, f7: n200 = () => {}, f8: n201 = () => {}, f9: n202 = () => {}, f10: n203 = () => {}, f11: n204 = () => {}, f12: n205 = () => {}, f13: n206 = () => {}, f14: n207 = () => {}, f15: n208 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o13: { f0: n209 = () => {}, f1: n210 = () => {}, f2: n211 = () => {}, f3: n212 = () => {}, f4: n213 = () => {}, f5: n214 = () => {}, f6: n215 = () => {}, f7: n216 = () => {}, f8: n217 = () => {}, f9: n218 = () => {}, f10: n219 = () => {}, f11: n220 = () => {}, f12: n221 = () => {}, f13: n222 = () => {}, f14: n223 = () => {}, f15: n224 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o14: { f0: n225 = () => {}, f1: n226 = () => {}, f2: n227 = () => {}, f3: n228 = () => {}, f4: n229 = () => {}, f5: n230 = () => {}, f6: n231 = () => {}, f7: n232 = () => {}, f8: n233 = () => {}, f9: n234 = () => {}, f10: n235 = () => {}, f11: n236 = () => {}, f12: n237 = () => {}, f13: n238 = () => {}, f14: n239 = () => {}, f15: n240 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o15: { f0: n241 = () => {}, f1: n242 = () => {}, f2: n243 = () => {}, f3: n244 = () => {}, f4: n245 = () => {}, f5: n246 = () => {}, f6: n247 = () => {}, f7: n248 = () => {}, f8: n249 = () => {}, f9: n250 = () => {}, f10: n251 = () => {}, f11: n252 = () => {}, f12: n253 = () => {}, f13: n254 = () => {}, f14: n255 = () => {}, f15: n256 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} } } = { o0: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o1: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o2: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o3: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o4: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o5: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o6: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o7: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o8: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o9: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o10: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o11: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o12: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o13: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o14: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o15: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} } }) {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R13b": { + "files": { + "a.ts": "// valid programs: tsc reports nothing but the sentinel\nfunction method({ o = { m() {} } } = { o: { m() {} } }) {}\nfunction inArray({ a = [() => {}] } = { a: [() => {}] }) {}\nfunction inObject({ a = { f: () => {} } } = { a: { f: () => {} } }) {}\nfunction sibling({ a = () => {}, b = () => a } = { a: () => {}, b: () => () => {} }) {}\nconst { s1 = () => s2, s2 = () => s1 } = { s1: () => 1, s2: () => 2 };\nconst { v = { f: () => {} } } = { v: { f: () => {} } };\nconst [w = [() => {}]] = [[() => {}]];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R16a": { + "files": { + "a.ts": "type J = S & { k: 1 };\nnamespace N18 { export type J = I037 & { k: 1 }; }\nnamespace N27 { export type J = I055 & { k: 1 }; }\nnamespace N36 { export type J = I073 & { k: 1 }; }\nnamespace N38 { export type J = I077 & { k: 1 }; }\nnamespace N40 { export type J = I081 & { k: 1 }; }\nnamespace N61 { export type J = I123 & { k: 1 }; }\nnamespace N77 { export type J = I155 & { k: 1 }; }\nnamespace N92 { export type J = I185 & { k: 1 }; }\nnamespace N105 { export type J = I211 & { k: 1 }; }\nnamespace N112 { export type J = I225 & { k: 1 }; }\ninterface I002 { p2: 1 }\ninterface I008 { p8: 1 }\ninterface I026 { p26: 1 }\ninterface I028 { p28: 1 }\ninterface I037 { p37: 1 }\ninterface I044 { p44: 1 }\ninterface I055 { p55: 1 }\ninterface I073 { p73: 1 }\ninterface I077 { p77: 1 }\ninterface I081 { p81: 1 }\ninterface I098 { p98: 1 }\ninterface I123 { p123: 1 }\ninterface I128 { p128: 1 }\ninterface I155 { p155: 1 }\ninterface I185 { p185: 1 }\ninterface I200 { p200: 1 }\ninterface I204 { p204: 1 }\ninterface I206 { p206: 1 }\ninterface I211 { p211: 1 }\ninterface I214 { p214: 1 }\ninterface I225 { p225: 1 }\ndeclare const v42: N27.J | N61.J | J<55, I128> | N77.J | J<19, I200> | N40.J | J<12, I214> | N38.J | N18.J | J<105, I028> | N36.J | J<106, I026> | J<16, I206> | J<70, I098> | J<17, I204> | N92.J | J<118, I002> | N105.J | J<115, I008> | J<97, I044> | N112.J;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R17": { + "files": { + "a.ts": "interface A { a: 1 } interface B { b: 2 }\ndeclare const x: Partial; declare const y: Partial | string;\nconst a1: never = [x, y];\nconst a2: never = [y, x];\nconst c1: never = Math.random() ? x : y;\nconst c2: never = Math.random() ? y : x;\ndeclare const x2: Partial; declare const y2: Partial | undefined;\nconst a3: never = [x2, y2];\nconst c3: never = Math.random() ? x2 : y2;\n// the same without a primitive member, and without subtype reduction: the two agree\ndeclare const x3: Partial; declare const y3: Partial | Partial;\nconst a4: never = [x3, y3];\nconst c4: never = Math.random() ? x3 : y3;\ndeclare const u: typeof x | typeof y; const n: never = u;\nconst a5: never = [x, x];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R18": { + "files": { + "a.ts": "type Props = Readonly<{ x: number }>;\ninterface Box { p: Props; v: T }\ntype GA = { p: Props; t: T };\ndeclare const b: Box;\ndeclare const u0: Props | Box[\"p\"]; const n0: never = u0;\ndeclare const u1: [Props] | [typeof b.p]; const n1: never = u1;\ndeclare const u2: [Props] | [Box[\"p\"]]; const n2: never = u2;\ndeclare const u3: [Props] | [GA[\"p\"]]; const n3: never = u3;\ndeclare const u4: Props & Box[\"p\"]; const n4: never = u4;\n// right since batch 1: the return type of a generic function, an element of a generic tuple alias\ndeclare function g(t: T): Props; const r = g(1); declare const u5: [Props] | [typeof r]; const n5: never = u5;\ntype GT = [Props, T]; declare const u6: [Props] | [GT<1>[0]]; const n6: never = u6;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "73-R19": { + "files": { + "a.ts": "namespace NS {\n type LU = Partial<{ a: 1 } | { b: 1 }>; type GT = [LU, T];\n const n1: never = null! as [LU] | [GT<1>[0]];\n}\n{\n type LU = Partial<{ a: 1 } | { b: 1 }>; type GT = [LU, T];\n const n2: never = null! as [LU] | [GT<1>[0]];\n}\n// at the top level of the file the alias is isNonGenericTopLevelType: one type in both\ntype TU = Partial<{ a: 1 } | { b: 1 }>; type TGT = [TU, T];\nconst n3: never = null! as [TU] | [TGT<1>[0]];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "74-R09a": { + "files": { + "a.tsx": "declare global { namespace JSX { interface IntrinsicElements { [k: string]: any } } }\nexport function List(props: { items: { name: string }[] }) {\n return
    {props.items.map(package =>
  • {package.name}
  • )}
;\n}\nexport const frag = <>{[1].map(static => static)};\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "74-R09b": { + "files": { + "a.tsx": "declare global { namespace JSX { interface IntrinsicElements { [k: string]: any } } }\nexport function Button() {\n return ;\n}\nexport function Input(public: any) {\n return ;\n}\nexport class View { render() { return
static}>
; } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "74-R09c": { + "files": { + "a.tsx": "declare namespace JSX { interface IntrinsicElements { [k: string]: any } }\nconst a =
;\nconst b =
1}>{function arguments() {}}
;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "74-R13a": { + "files": { + "a.ts": "let f: (a: string, ...\n", + "b.ts": "interface I { m(...\n// c\n", + "c.ts": "type F = new (a, @dec ", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "74-R13b": { + "files": { + "a.ts": "x = (...\n", + "b.ts": "x = async (... // c", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "74-R15a": { + "files": { + "a.ts": "export const e1: 0 = (a: unknown): a is string => true;\nexport const e2: 0 = (a: T): asserts a is T => {};\nexport const e3: 0 = { f(a: unknown): a is string { return true; } };\ndeclare function take(n: 0): void; take(function (a: unknown, b: unknown): b is string { return true; });\nexport const e5: (a: unknown) => a is number = (a: unknown): a is string => true;\n// controls: tsc reports these too\nexport const c1 = (a: unknown): a is string => true;\nexport const c2: 0 = [(a: unknown): a is string => true];\nexport function c3(a: unknown): a is string { return true; } export const c4: 0 = c3;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedParameters\": true } }\n" + } + }, + "74-R15b": { + "files": { + "a.ts": "declare const cond: boolean, x: unknown; type Fn = (n: number) => number;\nexport const f = cond ? (x) : n => n + 1;\nexport const g = [cond ? (x) : (n: number) => n, cond ? (x) : n => n ? 1 : 2];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "74-R15c": { + "files": { + "a.ts": "export {}; declare function async(x: T): T; declare const x: number; type U = number;\nasync (x);\n", + "b.ts": "export {}; declare function async(x: T): T; declare const x: number; type U = number; type T = number;\nasync (x);\n", + "c.ts": "export {}; declare function async(x: T): T; declare const x: number; type U = number; type T = number;\nasync (x);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "74-R15d": { + "files": { + "a.ts": "export {};\nconst q = (x: await) => x;\n", + "b.ts": "export {};\nconst q = (x: T) => x;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "74-R15e": { + "files": { + "a.ts": "declare const x: any; type T = any;\n(x?: number);\n", + "b.ts": "declare const x2: any, y2: any; type T2 = any;\n(x2? = 1);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "74-R16a": { + "files": { + "a.tsx": "switch (
\n<<<<<<< x\n) {}\n", + "b.tsx": "switch (\n<<<<<<< x) {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "74-R16b": { + "files": { + "a.tsx": "switch (1) { case \n<<<<<<< x\n: }\n", + "b.tsx": "switch (1) { case \n<<<<<<< x: }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "74-R16c": { + "files": { + "a.tsx": "function f(a = \n<<<<<<< x\n) {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "74-R19": { + "files": { + "a.ts": "declare function need(n: number): number;\nconst a1: number = Symbol.iterator;\nvar d1 = { x: need(Symbol.iterator), y: d1 };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "75-R01": { + "files": { + "a.ts": "declare function f(x: T): T;\ndeclare const v1: (typeof f);\nconst n1: number = v1;\ndeclare const v2: { a: (typeof f) };\nconst n2: number = v2;\ntype Q = (typeof f) | null;\ndeclare const v3: Q;\nconst n3: number = v3;\ndeclare const v4: (typeof f) | null;\nconst n4: number = v4;\ndeclare const v5: (typeof f)[];\nconst n5: number = v5;\ndeclare const v6: ( /* c */ typeof f );\nconst n6: number = v6;\nfunction g(p: (typeof f) | undefined) { const n7: number = p; }\nlet v8 = null! as (typeof f);\nconst n8: number = v8;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "75-R01b": { + "files": { + "b.js": "/** @typedef {{ q: string= }} T1 */\n/** @typedef {{ q: string=}} T2 */\n/** @typedef {{ q: string= }} T3 */\n/** @type {{ q: string= , r: number }} */\nlet v4;\n/** @typedef {{ q: string= 1 }} T5 */\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "75-R02": { + "files": { + "a.ts": "import { make, make2, make3, cls } from \"./m\";\nexport const v = make();\nexport const v2 = make2();\nexport const v3 = make3();\nexport const v4 = cls();\nexport function f(p = make()) { return [make2()]; }\nexport class C { p = make(); static s = make2(); m() { return make3(); } }\nconst sentinel: number = \"\";\n", + "m.ts": "namespace N { export default class Foo { x = 1 } }\nnamespace N2 { export default class { y = 1 } }\nnamespace N3 { export default interface Ifc { z: number } }\nexport function make() { return new N.default(); }\nexport function make2() { return new N2.default(); }\nexport function make3() { return null! as N3.default; }\nexport function cls() { return N.default; }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"declaration\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "75-R06": { + "files": { + "p1.ts": "import * as n1 from \"./p2\"; export { n1, n1 as m1 }; export default 1;\n", + "p2.ts": "import * as n2 from \"./p1\"; import * as o2 from \"./p1\"; export { n2, o2 };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{\"compilerOptions\":{\"strict\":true,\"noEmit\":true,\"types\":[],\"lib\":[\"es2022\"],\"module\":\"esnext\",\"moduleResolution\":\"bundler\"},\"files\":[\"p1.ts\",\"p2.ts\"]}\n" + } + }, + "75-R07": { + "files": { + "main.ts": "import { n1 } from \"./p1\";\nn1.nope;\nconst sentinel: number = \"\";\n", + "p1.ts": "import * as n1 from \"./p2\"; export { n1 };\nexport const v1 = 1;\n", + "p10.ts": "import * as n10 from \"./p11\"; export { n10 };\nexport const v10 = 10;\n", + "p11.ts": "import * as n11 from \"./p12\"; export { n11 };\nexport const v11 = 11;\n", + "p12.ts": "import * as n12 from \"./p13\"; export { n12 };\nexport const v12 = 12;\n", + "p13.ts": "import * as n13 from \"./p14\"; export { n13 };\nexport const v13 = 13;\n", + "p14.ts": "import * as n14 from \"./p15\"; export { n14 };\nexport const v14 = 14;\n", + "p15.ts": "import * as n15 from \"./p16\"; export { n15 };\nexport const v15 = 15;\n", + "p16.ts": "import * as n16 from \"./p17\"; export { n16 };\nexport const v16 = 16;\n", + "p17.ts": "import * as n17 from \"./p18\"; export { n17 };\nexport const v17 = 17;\n", + "p18.ts": "import * as n18 from \"./p19\"; export { n18 };\nexport const v18 = 18;\n", + "p19.ts": "import * as n19 from \"./p20\"; export { n19 };\nexport const v19 = 19;\n", + "p2.ts": "import * as n2 from \"./p3\"; export { n2 };\nexport const v2 = 2;\n", + "p20.ts": "import * as n20 from \"./p21\"; export { n20 };\nexport const v20 = 20;\n", + "p21.ts": "import * as n21 from \"./p22\"; export { n21 };\nexport const v21 = 21;\n", + "p22.ts": "import * as n22 from \"./p23\"; export { n22 };\nexport const v22 = 22;\n", + "p23.ts": "import * as n23 from \"./p24\"; export { n23 };\nexport const v23 = 23;\n", + "p24.ts": "import * as n24 from \"./p25\"; export { n24 };\nexport const v24 = 24;\n", + "p25.ts": "import * as n25 from \"./p26\"; export { n25 };\nexport const v25 = 25;\n", + "p26.ts": "import * as n26 from \"./p27\"; export { n26 };\nexport const v26 = 26;\n", + "p27.ts": "import * as n27 from \"./p28\"; export { n27 };\nexport const v27 = 27;\n", + "p28.ts": "import * as n28 from \"./p29\"; export { n28 };\nexport const v28 = 28;\n", + "p29.ts": "import * as n29 from \"./p30\"; export { n29 };\nexport const v29 = 29;\n", + "p3.ts": "import * as n3 from \"./p4\"; export { n3 };\nexport const v3 = 3;\n", + "p30.ts": "import * as n30 from \"./p31\"; export { n30 };\nexport const v30 = 30;\n", + "p31.ts": "import * as n31 from \"./p32\"; export { n31 };\nexport const v31 = 31;\n", + "p32.ts": "import * as n32 from \"./p33\"; export { n32 };\nexport const v32 = 32;\n", + "p33.ts": "import * as n33 from \"./p34\"; export { n33 };\nexport const v33 = 33;\n", + "p34.ts": "import * as n34 from \"./p35\"; export { n34 };\nexport const v34 = 34;\n", + "p35.ts": "import * as n35 from \"./p36\"; export { n35 };\nexport const v35 = 35;\n", + "p36.ts": "import * as n36 from \"./p37\"; export { n36 };\nexport const v36 = 36;\n", + "p37.ts": "import * as n37 from \"./p38\"; export { n37 };\nexport const v37 = 37;\n", + "p38.ts": "import * as n38 from \"./p39\"; export { n38 };\nexport const v38 = 38;\n", + "p39.ts": "import * as n39 from \"./p40\"; export { n39 };\nexport const v39 = 39;\n", + "p4.ts": "import * as n4 from \"./p5\"; export { n4 };\nexport const v4 = 4;\n", + "p40.ts": "import * as n40 from \"./p41\"; export { n40 };\nexport const v40 = 40;\n", + "p41.ts": "import * as n41 from \"./p42\"; export { n41 };\nexport const v41 = 41;\n", + "p42.ts": "import * as n42 from \"./p43\"; export { n42 };\nexport const v42 = 42;\n", + "p43.ts": "import * as n43 from \"./p44\"; export { n43 };\nexport const v43 = 43;\n", + "p44.ts": "import * as n44 from \"./p45\"; export { n44 };\nexport const v44 = 44;\n", + "p45.ts": "import * as n45 from \"./p46\"; export { n45 };\nexport const v45 = 45;\n", + "p46.ts": "import * as n46 from \"./p47\"; export { n46 };\nexport const v46 = 46;\n", + "p47.ts": "import * as n47 from \"./p48\"; export { n47 };\nexport const v47 = 47;\n", + "p48.ts": "import * as n48 from \"./p49\"; export { n48 };\nexport const v48 = 48;\n", + "p49.ts": "import * as n49 from \"./p50\"; export { n49 };\nexport const v49 = 49;\n", + "p5.ts": "import * as n5 from \"./p6\"; export { n5 };\nexport const v5 = 5;\n", + "p50.ts": "import * as n50 from \"./p51\"; export { n50 };\nexport const v50 = 50;\n", + "p51.ts": "import * as n51 from \"./p1\"; export { n51 };\nexport const v51 = 51;\n", + "p6.ts": "import * as n6 from \"./p7\"; export { n6 };\nexport const v6 = 6;\n", + "p7.ts": "import * as n7 from \"./p8\"; export { n7 };\nexport const v7 = 7;\n", + "p8.ts": "import * as n8 from \"./p9\"; export { n8 };\nexport const v8 = 8;\n", + "p9.ts": "import * as n9 from \"./p10\"; export { n9 };\nexport const v9 = 9;\n", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\"}, \"files\": [\"main.ts\"]}" + } + }, + "75-R07b": { + "files": { + "main.ts": "namespace M { export const v = 1; }\nimport a1 = a2;\nimport a2 = a3;\nimport a3 = a4;\nimport a4 = a5;\nimport a5 = a6;\nimport a6 = a7;\nimport a7 = a8;\nimport a8 = a9;\nimport a9 = a10;\nimport a10 = a11;\nimport a11 = a12;\nimport a12 = a13;\nimport a13 = a14;\nimport a14 = a15;\nimport a15 = a16;\nimport a16 = a17;\nimport a17 = a18;\nimport a18 = a19;\nimport a19 = a20;\nimport a20 = a21;\nimport a21 = a22;\nimport a22 = a23;\nimport a23 = a24;\nimport a24 = a25;\nimport a25 = a26;\nimport a26 = a27;\nimport a27 = a28;\nimport a28 = a29;\nimport a29 = a30;\nimport a30 = a31;\nimport a31 = a32;\nimport a32 = a33;\nimport a33 = a34;\nimport a34 = a35;\nimport a35 = a36;\nimport a36 = a37;\nimport a37 = a38;\nimport a38 = a39;\nimport a39 = a40;\nimport a40 = a41;\nimport a41 = a42;\nimport a42 = a43;\nimport a43 = a44;\nimport a44 = a45;\nimport a45 = a46;\nimport a46 = a47;\nimport a47 = a48;\nimport a48 = a49;\nimport a49 = a50;\nimport a50 = a51;\nimport a51 = a52;\nimport a52 = a53;\nimport a53 = a54;\nimport a54 = a55;\nimport a55 = a56;\nimport a56 = a57;\nimport a57 = a58;\nimport a58 = a59;\nimport a59 = a60;\nimport a60 = a61;\nimport a61 = a62;\nimport a62 = a63;\nimport a63 = a64;\nimport a64 = a65;\nimport a65 = a66;\nimport a66 = a67;\nimport a67 = a68;\nimport a68 = a69;\nimport a69 = a70;\nimport a70 = a71;\nimport a71 = a72;\nimport a72 = a73;\nimport a73 = a74;\nimport a74 = a75;\nimport a75 = a76;\nimport a76 = a77;\nimport a77 = a78;\nimport a78 = a79;\nimport a79 = a80;\nimport a80 = a81;\nimport a81 = a82;\nimport a82 = a83;\nimport a83 = a84;\nimport a84 = a85;\nimport a85 = a86;\nimport a86 = a87;\nimport a87 = a88;\nimport a88 = a89;\nimport a89 = a90;\nimport a90 = a91;\nimport a91 = a92;\nimport a92 = a93;\nimport a93 = a94;\nimport a94 = a95;\nimport a95 = a96;\nimport a96 = a97;\nimport a97 = a98;\nimport a98 = a99;\nimport a99 = a100;\nimport a100 = a101;\nimport a101 = a1;\na1.nope;\nexport {};\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\"}, \"files\": [\"main.ts\"]}" + } + }, + "75-R18": { + "files": { + "a.ts": "declare function cb(f: () => T): T;\nconst [a1, b1 = () => a1] = [1, () => 2];\nconst { a2, b2 = () => a2 } = { a2: 1, b2: () => 2 };\nconst [a3, b3 = () => a3] = cb(() => [1, () => 2]);\nfunction f4([a4, b4 = () => a4] = [1, () => 2]) {}\nconst [a5, b5 = { m: () => a5 }] = [1, { m: () => 2 }];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "75-R18c": { + "files": { + "a.ts": "declare function cb(f: () => T): T;\nconst [a, b = () => 1] = cb(() => [1, () => 2]);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "76-R05a": { + "files": { + "a.ts": "interface A { a: number }\ninterface B { b: number }\ninterface X5 extends A, B { [k: string]: X5[\"a\"] }\ndeclare const x5: X5;\nconst y5: number = x5.zzz;\nfunction f5(x: X5) { const r: number = x.zzz; }\ninterface Y5 extends X5 { more: 1 }\ndeclare const yy5: Y5;\nconst z5: number = yy5.zzz;\n// in tsc only the instantiation that the index signature names loses it\ninterface X8 extends A, B { [k: string]: X8[\"a\"] }\ndeclare const x8: X8;\nconst y8: number = x8.zzz;\ndeclare const x8n: X8;\nconst y8n: number = x8n.zzz;\n// an interface with `this`: the type itself loses it, an interface derived from it does not\ninterface X9 extends A, B { self: this; [k: string]: X9[\"a\"] | this }\ndeclare const x9: X9;\nconst y9: number | X9 = x9.zzz;\ninterface Y9 extends X9 { more: 1 }\ndeclare const yy9: Y9;\nconst z9: number | Y9 = yy9.zzz;\n// one base: the two agree\ninterface X7 extends A { [k: string]: X7[\"a\"] }\ndeclare const x7: X7;\nconst y7: number = x7.zzz;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "76-R05b": { + "files": { + "a.ts": "interface A { a: number }\ninterface B { b: number }\ninterface X2 extends A, B { own: \"late\"; [k2]: number }\ndeclare const k2: X2[\"own\"];\ndeclare const x2: X2;\nconst y2: number = x2.late;\nconst o2: X2 = { a: 1, b: 2, own: \"late\", late: 3 };\n// one base: the two agree, `late` is a member\ninterface X3 extends A { own: \"late\"; [k3]: number }\ndeclare const k3: X3[\"own\"];\ndeclare const x3: X3;\nconst y3: number = x3.late;\n// a class merged with the interface\nclass C4 { own!: \"late\"; [k4]!: number }\ninterface C4 extends A, B {}\ndeclare const k4: C4[\"own\"];\ndeclare const x4: C4;\nconst y4: number = x4.late;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "76-R05c": { + "files": { + "a.ts": "declare const w1: { readonly p: keyof W1 };\ninterface W1 { x(): void; [w1.p](): void }\ndeclare const w2: { readonly p: keyof W2 };\ninterface W2 { x: 1; [w2.p]: number }\ndeclare const w3: { readonly p: W3 extends { x: 1 } ? \"a\" : \"b\" };\ninterface W3 { x: 1; [w3.p]: number }\ndeclare class H4 { readonly p: keyof W4 }\ndeclare const h4: H4;\ninterface W4 { x(): void; [h4.p](): void }\n// `p` is asked for before its declaration is checked: the two agree\nw5.p;\ndeclare const w5: { readonly p: keyof W5 };\ninterface W5 { x(): void; [w5.p](): void }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "76-R11": { + "files": { + "a.ts": "export {};\ndeclare const anyV: any;\ndeclare function pair(a: A, b: A): [A, A];\n// an omitted element is a plain `any`: a candidate for A beside `[any, any]`, so A is `any` in the return mapper and the literals are arrays\nconst [, [p1, q1]] = pair([1, \"a\"], [2, \"b\"]);\np1.toFixed();\nlet [, [p2, q2]] = pair([1, \"a\"], [2, \"b\"]);\nq2 = 5;\n// a default of type `any`\nconst [a3 = anyV, [p3, q3]] = pair([1, \"a\"], [2, \"b\"]);\np3.toFixed();\ndeclare function both(a: A): { p: A; q: A };\nconst { p: p4 = anyV, q: [r4, s4] } = both([1, \"a\"]);\nr4.toFixed();\nfunction f5([, [r, s]] = pair([1, \"a\"], [2, \"b\"])) { r.toFixed(); }\n// only names: the two agree, the literals are tuples\nconst [a6, [p6, q6]] = pair([1, \"a\"], [2, \"b\"]);\np6.toFixed(); q6.toFixed();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "76-R20": { + "files": { + "a.ts": "export {};\ndeclare const key: string;\nh1({});\nfunction h1({ [key]: a = 1, b = a }) {}\nfunction h2({ [key]: a = 1, b = a }) {}\nh2({});\nfunction h3({ [key]: a = 1, b = a }) {}\nh4({});\nfunction h4({ b = a, [key]: a = 1 }) {}\nh5({});\nfunction h5({ [key]: a = 1, b = () => a }) {}\nh6({});\nfunction h6({ x: { [key]: a = 1 }, b = a }) {}\nh7([]);\nfunction h7([{ [key]: a = 1 }, b = a]) {}\nconst h8 = function ({ [key]: a = 1, b = a }) {};\nconst h9 = ({ [key]: a = 1, b = a }) => {};\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R01a": { + "files": { + "a.ts": "const o1 = { set p({ a = null, b = undefined, c = [] }) { } };\nclass C1 { set p({ a = null, b = undefined, c = [] }) { } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": false, \"noImplicitAny\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R01b": { + "files": { + "a.ts": "const o1 = { set p({ a, b } = { a: null, b: undefined }) { } };\nconst o2 = { set p([a, b] = [null, undefined]) { } };\nconst o3 = { set p({ a } = { a: [] }) { } };\nclass C1 { set p({ a, b } = { a: null, b: undefined }) { } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": false, \"noImplicitAny\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R02a": { + "files": { + "a.ts": "declare function call(f: (x: T) => void, v: T): T;\ncall(({ a } = { a: 1 }) => {}, { a: 2 });\ncall(([a] = [1]) => {}, [2]);\ncall(({ a } = { a: 1, z: 1 }) => {}, { a: 2, y: 3 });\ncall((x = { a: 1 }) => {}, { a: 2 });\ndeclare function call3(o: { f: (x: T) => void, v: T }): T;\ncall3({ f({ a } = { a: 1 }) {}, v: { a: 2 } });\ndeclare function call6(f: (x: { p: T }) => void, v: T): T;\ncall6(({ p } = { p: 1 }) => {}, 2);\n[{ a: 1 }].map(({ a } = { a: 1 }) => a);\n[1].reduce(({ n } = { n: 0 }, x) => ({ n: n + x }), { n: 0 });\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R03a": { + "files": { + "a.ts": "declare const u: Unresolved;\nfunction* g1() { const r = yield* u; const t: never = r; }\nasync function* g2() { const r = yield* u; const t: never = r; }\nfunction* g3(): Generator { const r = yield* u; const t: never = r; }\nfunction* g4() { for (const x of u) { const t: never = x; } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R12a": { + "files": { + "a.jsx": "/** @param {number} a @param {number} extra */\nfunction h1(a) { return ; }\n/** @param {number} a @param {number} extra */\nfunction h4(a) { return
; }\n/** @param {number} a @param {number} extra */\nfunction h7(a) { return ; }\n/** @param {number} a @param {number} extra */\nfunction h3(a) { return
; }\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"jsx\": \"preserve\", \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R12b": { + "files": { + "a.jsx": "/** @param {number} a @param {number} extra */\nfunction s1(a) { switch (a) { case
: let arguments = 1; } }\n/** @param {number} a @param {number} extra */\nfunction s5(a) { switch (a) { case 1: let arguments = 1; break; case
: break; } }\n/** @param {number} a @param {number} extra */\nfunction s8(a) { { const x =
; let arguments = 1; } }\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"jsx\": \"preserve\", \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R12c": { + "files": { + "a.js": "/** @param {number} a @param {number} extra */\nfunction g3(a) { return class { arguments = 1; constructor(arguments) {} }; }\n/** @param {number} a @param {number} extra */\nfunction g1(a) { return class { arguments = 1; }; }\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"useDefineForClassFields\": false, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R12d": { + "files": { + "a.ts": "function f() { return class { p = arguments; constructor(arguments: any) {} }; }\nfunction g() { return class { p = arguments; }; }\nclass C1 { p = arguments; constructor(arguments: any) {} }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"useDefineForClassFields\": false, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R13a": { + "files": { + "a.js": "/** @param {any} a @param {number} extra */\nfunction t(a) { const x = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1; return arguments; }\n/** @type {number} */\nconst sentinel = \"\";\n", + "bun.stderr.txt": "error: ran out of stack in a.js. This is a bug in Bun: errors in this file may be missing.\nCould not finish checking 1 file, checked 58 files [10.60ms]\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R13b": { + "files": { + "a.ts": "function t() { if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else {} }\nconst sentinel: number = \"\";\n", + "bun.stderr.txt": "\nthread '' (140071976) has overflowed its stack\nfatal runtime error: stack overflow, aborting\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, + "77-R17a": { + "files": { + "a.js": "/** @param {never} x */\nfunction nv(x) {}\nclass A1 { constructor() { this.a = null; this.a = \"s\"; } a; }\nclass A2 { a; constructor() { this.a = null; this.a = \"s\"; } }\nclass A3 { constructor() { this.a = 1; nv(this.a); this.a = \"s\"; nv(this.a); } a; m() { nv(this.a); } }\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R17b": { + "files": { + "a.ts": "class C { constructor(public a: number, public a: string) {} }\nnew C(1, \"\"); new C(1, 2);\nclass D { constructor(a: number, a: string) {} }\nnew D(1, \"\"); new D(1, 2);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "77-R19a": { + "files": { + "a.ts": "interface Array { 0: string; }\ndeclare function f(...a: number[]): void;\nf(\"s\"); f(1); f(\"s\", 1);\ndeclare function g(...cbs: ((x: number) => void)[]): void;\ng(\"s\", y => { const t: never = y; });\nconst fn: (a: number) => void = f;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "78-R01": { + "files": { + "a.ts": "declare function f1(cb: () => { a: (x: number) => void; v?: unknown }, t: T): T;\ndeclare function f3(cb: () => { a: (x: number) => void; v?: T }, t: T): T;\nfunction g1() { return f1(() => ({ a: x => {}, v: g1() }), 1); }\nfunction g3() { return f3(() => ({ a: x => {}, v: g3() }), 1); }\nfunction g7() { return f1(function () { return { a: x => {}, v: g7() }; }, 1); }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "78-R03": { + "files": { + "a.ts": "declare function inject(): U;\nfunction g1(q: Q) { return inject() satisfies (y: Q) => T[]; }\ng1(1)(2);\nconst ok1: (y: number) => unknown = g1(1);\nclass Box { handlers = { on: inject() } satisfies { on(y: Q): T | undefined }; }\nnew Box().handlers.on(\"s\");\ng1(1).zzz;\n// a call signature is not instantiated in tsc either\nfunction g2(q: Q) { return inject() satisfies { (y: Q): T[] }; }\ng2(1).zzz;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "78-R07": { + "files": { + "a.ts": "function q1(a = await 1): void; function q1(a: any) {}\nfunction q2(a = (await \"s\")): void; function q2(a: any) {}\nfunction q3(a = await await true): void; function q3(a: any) {}\ndeclare function q4(a = await 1): void; q4();\nclass K { m(a = await 1): void; m(a: any) {} }\n// tsc reports these: the operand is not a literal, or the initializer is not the `await` itself\nfunction r1(a = await -1): void; function r1(a: any) {}\nfunction r2(a = [await 1]): void; function r2(a: any) {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "78-R20b": { + "files": { + "a.ts": "function o1(a: {}): void; function o1({ x = null }) {}\nfunction o2(a: {}): void; function o2({ x = undefined, y = [], z = { w: null } }) {}\nclass O3 { m(a: {}): void; m({ x = null }) {} constructor(a: {}); constructor({ x = null }) {} }\nexport function o4(): void; export function o4({ x = null } = {}) {}\n// both report: no overloads\nfunction p1({ x = null }) {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"strictNullChecks\": false, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "78-R20d": { + "files": { + "a.ts": "declare const key: string;\nfunction o1(a: {}): void; function o1({ [key]: a = 1 }) {}\nclass O2 { m(a: {}): void; m({ [key]: a = 1 }) {} }\n// both report TS2537: a call before the declaration\ne3({}); function e3({ [key]: a = 1 }) {}\n// both are silent\nfunction e4({ [key]: a = 1 }) {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "79-R03a": { + "files": { + "a.ts": "type F3 = X extends (infer A extends F3) ? A : never;\ntype F8 = X extends [infer A extends F8[]] ? A : never;\ntype H4 = X extends [infer A extends keyof H4] ? A : never;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "79-R03b": { + "files": { + "a.ts": "type F4 = X extends [infer A extends F4] ? A : never;\ntype F6 = X extends [infer A extends F6] ? A : never;\ntype W3 = X extends [infer A extends typeof w3] ? A : never; declare const w3: W3<[1]>;\ntype W6 = X extends [infer A extends W7[\"p\"]] ? A : never; interface W7 { p: W6<[1]> }\nfunction fn(x: X extends [infer A extends ReturnType] ? A : never) { return x; }\nclass Cl { p!: X extends [infer A extends Cl[\"p\"]] ? A : never; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "79-R03c": { + "files": { + "a.ts": "interface M3 { a: T } interface M3 { b: U }\ninterface M6 { a: T } interface M6 { b: T }\nclass M9 { a!: T } interface M9 { b: T }\ninterface M11[\"a\"]> { a: T } interface M11[\"a\"]> { b: T }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "79-R05": { + "files": { + "a.ts": "const a1: \"\" = `${2 ** -25}`;\nconst a2: never = 2.98023223876953125e-8;\nconst a3: never = 713680496268224.25;\nconst a4: never = 258555422826684.625;\nenum E { B = 1 / 33554432 } const a5: \"\" = `${E.B}`;\nconst o = { 713680496268224.25: 1 }; o[\"713680496268224.2\"]; o[\"713680496268224.3\"];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "79-R11": { + "files": { + "j.js": "class B { constructor() { this.x = new B().x; } m() { return this.x; } }\nclass D { constructor() { this.x = mk().x; } m() { return this.x; } } /** @returns {D} */ function mk() { return new D(); }\nclass E { constructor() { const t = mk2().x; this.x = t; } m() { return this.x; } } /** @returns {E} */ function mk2() { return new E(); }\nclass K { constructor() { this.x = new K; this.y = new K().x.y; } m() { return [this.x, this.y]; } }\nclass O { constructor(/** @type {O} */ o) { this.x = o.x; } m() { return this.x; } }\n/** @type {number} */ const sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "80-R01a": { + "files": { + "a.ts": "type T1 = typeof import(\"./x\", { with: { #constructor: \"a\" } });\ntype T2 = import(\"./x\", { with: { #constructor: \"a\" } }).A;\nimport { a as a3 } from \"./x\" with { #constructor: \"a\" };\nexport * from \"./x\" with { #constructor: \"b\" };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"jsx\": \"preserve\" } }\n", + "x.ts": "export const a = 1; export type A = number;\n" + } + }, + "80-R01b": { + "files": { + "a.tsx": "declare namespace JSX { interface IntrinsicElements { div: any } interface Element {} }\nconst j1 =
;\nconst j2 =
;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"jsx\": \"preserve\" } }\n" + } + }, + "80-R01c": { + "files": { + "a.ts": "const m1 = import.#constructor;\nconst m2 = import.#meta;\nclass K { #a = 1; m() { return import.#a; } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"jsx\": \"preserve\" } }\n" + } + }, + "80-R04": { + "files": { + "a.ts": "declare export default (() => { for (;;) { break; } })();\ndeclare const c = () => { { 1; } };\ndeclare enum E { A = (() => { if (1) { 1; } return 1 })() }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "80-R07": { + "files": { + "a.js": "@dec declare module \"zz\" {}\n@dec declare module \"yy\";\nfunction dec() {}\n/** @type {number} */ const sentinel = \"\";\n", + "b.js": "@dec export as namespace X;\n", + "c.js": "@dec declare global {}\nexport {};\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "80-R08": { + "files": { + "a.ts": "declare function dec(...a: any[]): any;\nconst c1 = @dec abstract class { abstract m(): void };\nconst c2 = @dec public class {};\nconst c3 = (@dec export default class {});\nnew c1();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\" } }\n" + } + }, + "80-R09a": { + "files": { + "a.ts": "let t1: new ({ a b }) => void;\n", + "b.ts": "let t2: { m({ a b }): void };\n", + "c.ts": "let t3: new ([ a b ]) => void;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\" } }\n" + } + }, + "80-R09b": { + "files": { + "a.js": "const v1 = { m() };\nconst v2 = { get a() };\nconst v3 = { async n() };\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "80-R09c": { + "files": { + "a.js": "function g(a: ) {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "80-R12a": { + "files": { + "a.js": "exports.a = 1;\n{ export { a as a2 } from \"./missing\"; }\n/** @type {number} */ const sentinel = \"\";\n", + "b.js": "exports.a = 1;\n{ export * as a6 from \"./missing\"; }\n", + "c.js": "exports.a = 1;\n{ export { zzz as a2 }; }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"moduleDetection\": \"force\" } }\n" + } + }, + "80-R13a": { + "files": { + "0.ts": "import d from \"./a\";\nd;\n", + "a.ts": "import \"./0\";\nimport y from \"./a\";\nexport default Missing;\n", + "b.ts": "import other from \"./r\";\nexport default Missing;\n", + "r.ts": "export { default } from \"./b\";\n", + "s.ts": "const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"commonjs\", \"esModuleInterop\": true }, \"files\": [\"a.ts\", \"b.ts\", \"s.ts\"] }\n" + } + }, + "80-R13b": { + "files": { + "a.ts": "import Missin from \"./a\";\nexport default Missing;\n", + "b.ts": "export default Missing;\nimport Missin from \"./b\";\n", + "c.ts": "import Missin = require(\"./c\");\nexport = Missing;\n", + "s.ts": "const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"commonjs\", \"esModuleInterop\": true } }\n" + } + }, + "80-R17a": { + "files": { + "a.ts": "import { X } from \"./m\";\n/** Sets things up, see {@link X}. */\n(function () {})();\nexport const sentinel: number = \"\";\n", + "b.ts": "import { X } from \"./m\";\n/** {@link X} */\n(globalThis as any).foo = 1;\nexport {};\n", + "m.ts": "export class X {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"noUnusedLocals\": true } }\n" + } + }, + "80-R17b": { + "files": { + "a.ts": "import { X } from \"./m\";\nexport const f =\n /** {@link X} */\n a => a;\nexport const sentinel: number = \"\";\n", + "m.ts": "export class X {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"noUnusedLocals\": true } }\n" + } + }, + "80-R17c": { + "files": { + "a.ts": "import { X } from \"./m\";\nexport class K {\n p = 1;\n /** {@link X} */\n ;\n}\nexport const sentinel: number = \"\";\n", + "m.ts": "export class X {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"noUnusedLocals\": true } }\n" + } + }, + "80-R18a": { + "files": { + "a.ts": "const A = { b: 1 };\nexport namespace W {\n namespace A {}\n export let t: A.b;\n}\nexport const sentinel: number = \"\";\n", + "b.ts": "class A { static q = 1 }\nexport namespace W {\n namespace A {}\n export import x = A.b;\n}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"commonjs\", \"noUnusedLocals\": true } }\n" + } + }, + "80-R18b": { + "files": { + "a.ts": "const A = { b: 1 };\nexport namespace W {\n interface A { b: 1 }\n export import x = A;\n}\nexport const sentinel: number = \"\";\n", + "b.ts": "class A { static b = 1 }\nexport namespace W {\n type A = { b: 1 };\n import x = A.b;\n x;\n}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"commonjs\", \"noUnusedLocals\": true } }\n" + } + }, + "80-R20b": { + "files": { + "a.ts": "function f1(t: T) {\n const r = { ...t, get a() { return \"g\"; } };\n r.a = \"x\";\n r.zzz;\n}\nclass K {\n constructor(public t: T) {}\n m() {\n const s = { ...this, b: 1, get c() { return 1; } };\n s.c = 2;\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\" } }\n" + } + }, + "81-R01": { + "files": { + "a.ts": "const kz = \"z\";\nconst v2 = { z: 1, get z() { return v2.z } };\nconst v3 = { [kz]: 1, get [kz]() { return v3.z } };\nconst v6 = { [kz]: 1, get z() { return v6.z } };\nconst w8 = { z: 1, set z(v: typeof w8) {} };\n// the plain member last, or no plain member: the two agree\nconst v9 = { get z() { return v9.z }, z: 1 };\nconst v1 = { get z() { return v1.z } };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "81-R01b": { + "files": { + "a.ts": "const kz = \"z\";\nconst w10 = { set z(v) {}, get [kz]() { return w10.z } };\nconst w11 = { get [kz]() { return w11.z }, set z(v) {} };\nconst w15 = { get [kz](): typeof w15.z { return 1 }, set z(v) {} };\n// a class, or the getter with the plain name: the two agree\nconst w12 = { set [kz](v) {}, get z() { return w12.z } };\nclass K1 { set z(v) {} get [kz]() { return this.z } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "81-R02": { + "files": { + "a.ts": "function a1(x: T) { return x!.toUpperCase(); }\nfunction a2(x: T) { return x!.toFixed(); }\nfunction a3(o: { p: T }) { return o.p!.length; }\nfunction a4(f: () => NonNullable) { return f().length; }\nclass A5 { p!: T; m() { return this.p!.length; } }\nfunction a6(x: T) { x!.length = 1; }\n// the two agree: a constraint that is still a union or an object type after `& {}`, a reference in a constraint position\nfunction b1(x: T) { return x!.toString(); }\nfunction b2(x: T) { return x!.a; }\nfunction b3(x: NonNullable) { return x.length; }\nfunction b4(x: T) { return x![0]; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "81-R03": { + "files": { + "a.ts": "export async function e1() {}\nexport class C { async m() {} }\nasync function local() {}\nexport { local };\n// not exported: not asked by the declaration emitter either\nasync function hidden() {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"declaration\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es5\"], \"target\": \"es2022\" } }\n" + } + }, + "81-R04": { + "files": { + "a.ts": "const s1 = { set a(v: typeof s1.a) {} };\nconst r1: null = s1;\nconst s7 = { set a(v: typeof s7.b) {}, set b(v: typeof s7.a) {} };\nconst r7: null = s7;\nconst s31 = { get a(): typeof s31.a { return 1 } };\nconst r31: null = s31;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "81-R09": { + "files": { + "a.ts": "const w1 = function (this: typeof w1, x = this) {};\nconst w3 = function (this: typeof w3, x: number, y = this) {};\nconst w7 = { m(this: typeof w7, x = this) {} };\nconst e2 = function (this: ReturnType, x = this) { return x; };\n// an ordinary first parameter, or a default that does not read `this` at once: the two agree\nconst w4 = function (a: typeof w4, x = a) {};\nconst w5 = function (this: typeof w5, x = () => this) {};\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "81-R09b": { + "files": { + "a.ts": "function h1(this: ReturnType, x = this) { return 1; }\nfunction h2(this: Parameters[0], x = this) {}\nfunction h3(this: ThisParameterType, x = [this]) {}\nfunction h8(this: ReturnType, x: typeof this) { return 1; }\nclass K1 { m(this: ReturnType, x = this) { return x; } }\n// an ordinary first parameter: the two agree\nfunction p1(a: ReturnType, x = a) { return x; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "81-R16": { + "files": { + "a.ts": "declare function run(f: () => T): T;\nfunction k6(ns: string[]) {\n let last: string | null = null;\n for (const n of ns) {\n if (n === last) continue;\n last = run(() => n);\n }\n}\nfunction k1(n: number, more: () => boolean) {\n let acc: number | null = null;\n while (more()) {\n if (n === acc) break;\n acc = [1].map(() => n)[0];\n }\n}\nasync function k21(y: \"a\" | \"b\", more: () => boolean) {\n let x: \"a\" | \"b\" = \"a\";\n while (more()) {\n if (y === x) { }\n x = await Promise.resolve().then(() => y);\n }\n}\n// the two agree: no initializer, a declared type that is no union, an annotated callback\nfunction a1(ns: string[]) { let last: string | undefined; for (const n of ns) { if (n === last) continue; last = run(() => n); } }\nfunction a2(ns: string[]) { let last = \"\"; for (const n of ns) { if (n === last) continue; last = run(() => n); } }\nfunction a3(ns: string[]) { let last: string | null = null; for (const n of ns) { if (n === last) continue; last = run((): string => n); } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "81-R16b": { + "files": { + "a.ts": "declare function apply(x: T, f: (v: T) => U): U;\nfunction sum(xs: number[]) {\n let acc: number | null = null;\n for (const n of xs) {\n acc = apply(acc, v => (v ?? 0) + n);\n }\n return acc;\n}\nfunction text(more: () => boolean) {\n let x: string | number = 0;\n while (more()) {\n x = apply(x, v => String(v));\n }\n}\n// the two agree: a method of an array, an annotated parameter, explicit type arguments\nfunction a1(xs: number[]) { let acc: number | null = null; for (const n of xs) { acc = [acc].map(v => (v ?? 0) + n)[0]; } }\nfunction a2(xs: number[]) { let acc: number | null = null; for (const n of xs) { acc = apply(acc, (v: number | null) => (v ?? 0) + n); } }\nfunction a3(xs: number[]) { let acc: number | null = null; for (const n of xs) { acc = apply(acc, v => (v ?? 0) + n); } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R02": { + "files": { + "a.ts": "declare function cond(): boolean;\nfunction f1() {\n let mode: \"r\" | \"w\" = \"r\";\n while (cond()) {\n const [m, n] = [mode, 1];\n switch (m) {\n case \"r\":\n mode = \"w\";\n break;\n }\n }\n}\nfunction f2() {\n let mode: \"r\" | \"w\" = \"r\";\n while (cond()) {\n const { m } = { m: mode };\n switch (m) {\n case \"r\":\n mode = \"w\";\n }\n const t: \"r\" | \"w\" = m;\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R03": { + "files": { + "a.ts": "declare function cond(): boolean;\ntype Item = { id: number; parent: Item | undefined; label: string };\nfunction walk(start: Item) {\n let item: Item | undefined = start;\n while (item) {\n const { id, ...rest } = item;\n item = rest.parent;\n }\n}\nfunction f1() {\n let n: 1 | 2 = 1;\n while (cond()) {\n const { a, ...rest } = { a: n, b: n };\n n = rest.b;\n }\n}\nfunction f2() {\n let n: 1 | 2 = 1;\n while (cond()) {\n const [a, ...rest] = [n, n];\n n = rest[0];\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R09": { + "files": { + "a.ts": "const o1 = { m(this) { return this; } };\nconst t1: null = o1;\nconst o2 = { m(this) { return 1; }, k: 1 };\nconst t2: null = o2;\nconst o3 = { f: function (this) { return this; } };\nconst t3: null = o3;\nconst o4 = { m(this, x: number) { return x; } };\no4.m = 1;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R13": { + "files": { + "a.ts": "function mk1() { return [new A1()]; }\nfunction mk2() { return [new A2()]; }\nclass A1 { bs = [new B1()] } class B1 { cs = [new C1()] } class C1 { ds = [new D1()] } class D1 { es = [new E1()] } class E1 { x = 1 }\nclass A2 { bs = [new B2()] } class B2 { cs = [new C2()] } class C2 { ds = [new D2()] } class D2 { es = [new E2()] } class E2 { x = \"\" }\nlet a1 = mk1(); let a2 = mk2();\na2 = a1;\nconst c: C2[] = new B1().cs;\nconst d: D2[] = new C1().ds;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R17": { + "files": { + "a.ts": "export * from \"x\"\n\\u0077ith (a) {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R17b": { + "files": { + "a.ts": "type T = A extends infer U \\u0065xtends B ? C : D;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R17c": { + "files": { + "a.ts": "\\u0065lse;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R17d": { + "files": { + "a.ts": "switch (a) { case 1: else {} }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R17e": { + "files": { + "a.ts": "f(\\u0065lse);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R19": { + "files": { + "a.ts": "\"a-\n017;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R19b": { + "files": { + "a.ts": "/a-\n017;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "82-R20": { + "files": { + "a.ts": "for (let \"x\";;) {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "83-R01b": { + "files": { + "i03.ts": "var v = new X(a);\n", + "i13.ts": "var v = new ;\n", + "j01.ts": "var v = f(a);\n", + "j06.ts": "var v = f(x);\n", + "j10.ts": "var v = f(x);\n", + "j13.ts": "var v = f(x);\n", + "j16.ts": "var v = f(x);\n", + "j17.ts": "var v = f(x);\n", + "j19.ts": "var v = f`x`;\n", + "j20.ts": "var v = f;\n", + "j21.ts": "var v = f.x;\n", + "j23.ts": "var v = a.b(x);\n", + "j32.ts": "var v = f(x);\n", + "j33.ts": "var v = f(x);\n", + "j34.ts": "var v = f<`${>(x);\n", + "j40.ts": "var v = f(x);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "83-R01c": { + "files": { + "k01.ts": "for (var i = (a = x in b) => 1;;) {}\n", + "k02.ts": "for (var i = (a = x in b) => 1;;) {}\n", + "k03.ts": "for (var i = async (a = x in b) => 1;;) {}\n", + "k04.ts": "for (var i = (a: any = x in b) => 1;;) {}\n", + "k07.ts": "for (var i = [x in b];;) {}\n", + "k11.ts": "for (var i = (a) => { x in b };;) {}\n", + "k14.ts": "for (var i = class { m(a = x in b) {} };;) {}\n", + "k15.ts": "for (var i = { m(a = x in b) {} };;) {}\n", + "k21.ts": "for (var i = (a, c = x in b) => 1;;) {}\n", + "k25.ts": "for (i = (a = x in b) => 1;;) {}\n", + "k31.ts": "for (var i = function () { x in b };;) {}\n", + "k32.ts": "for (var i = class { m() { x in b } };;) {}\n", + "k34.ts": "for (var i = [...x in b];;) {}\n", + "k35.ts": "for (var i = class { static { x in b } };;) {}\n", + "k36.ts": "for (var i = function () { y = x in b };;) {}\n", + "k38.ts": "for (var i = function () { lbl: x in b };;) {}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "83-R02a": { + "files": { + "a.tsx": "declare namespace JSX { interface Element {} interface ElementChildrenAttribute { children: {} } interface IntrinsicElements { div: { children?: unknown } } }\ndeclare function A(props: { children?: unknown }): JSX.Element;\ntype G = T;\nvar v1 = >=1;\nvar v2 = >= ;\nvar v3 = >>=1;\nvar v4 = >==1;\nvar v5 =
>=1
;\nvar v6 = >=1;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } + }, + "83-R03a": { + "files": { + "a01.ts": "class C { a = 1 st\\u0061tic \"\\x\" = 2 }\n", + "a03.ts": "class C { a = 1 st\\u0061tic 1__0 = 2 }\n", + "a04.ts": "class C { a = 1 st\\u0061tic \"x\n}\n", + "a05.ts": "class C { a = 1 st\\u0061tic\n<<<<<<< x\nb = 2 }\n", + "a06.ts": "class C { a = 1 publi\\u0063 \"\\x\" = 2 }\n", + "a08.ts": "class C { a = 1 g\\u0065t \"\\x\"() { return 1 } }\n", + "a10.ts": "class C { a = 1 \\u0061sync \"\\x\"() { } }\n", + "a15.ts": "class C { a = 1 st\\u0061tic 08 = 2 }\n", + "a19.ts": "class C { a = 1 g\\u0065t\n<<<<<<< x\nb() { return 1 } }\n", + "a20.ts": "var o = { a: 1 g\\u0065t \"\\x\"() { return 1 } }\n", + "a22.ts": "var o = { a: 1 \\u0061sync \"\\x\"() { } }\n", + "a23.ts": "var o = { a: 1 g\\u0065t\n<<<<<<< x\nb() { return 1 } }\n", + "a29.ts": "1 l\\u0065t\n<<<<<<< x\ny = 1\n", + "a38.ts": "1 modul\\u0065 \"\\x\" {}\n", + "a39.ts": "1 d\\u0065clare module \"\\x\" {}\n", + "b36.ts": "class C { a = 1 st\\u0061tic\n<<<<<<< x\n{ } }\n", + "b37.ts": "class C { a = 1 c\\u006fnstructor\n<<<<<<< x\n() { } }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "83-R03b": { + "files": { + "function_array.ts": "x = [f\\u0075nction () {}];\n", + "function_array2.ts": "x = [1, f\\u0075nction () {}];\n", + "function_arrow.ts": "x = () => f\\u0075nction () {};\n", + "function_call.ts": "f(f\\u0075nction () {});\n", + "function_call2.ts": "f(1, f\\u0075nction () {});\n", + "function_new.ts": "new X(f\\u0075nction () {});\n", + "function_opt.ts": "f?.(f\\u0075nction () {});\n", + "function_targ.ts": "f(f\\u0075nction () {});\n", + "import_array.ts": "x = [i\\u006dport(\"x\")];\n", + "import_array2.ts": "x = [1, i\\u006dport(\"x\")];\n", + "import_arrow.ts": "x = () => i\\u006dport(\"x\");\n", + "import_call.ts": "f(i\\u006dport(\"x\"));\n", + "import_call2.ts": "f(1, i\\u006dport(\"x\"));\n", + "import_new.ts": "new X(i\\u006dport(\"x\"));\n", + "import_opt.ts": "f?.(i\\u006dport(\"x\"));\n", + "import_targ.ts": "f(i\\u006dport(\"x\"));\n", + "new_array.ts": "x = [n\\u0065w X()];\n", + "new_array2.ts": "x = [1, n\\u0065w X()];\n", + "new_arrow.ts": "x = () => n\\u0065w X();\n", + "new_call.ts": "f(n\\u0065w X());\n", + "new_call2.ts": "f(1, n\\u0065w X());\n", + "new_new.ts": "new X(n\\u0065w X());\n", + "new_opt.ts": "f?.(n\\u0065w X());\n", + "new_targ.ts": "f(n\\u0065w X());\n", + "null_array.ts": "x = [n\\u0075ll];\n", + "null_array2.ts": "x = [1, n\\u0075ll];\n", + "null_arrow.ts": "x = () => n\\u0075ll;\n", + "null_call.ts": "f(n\\u0075ll);\n", + "null_call2.ts": "f(1, n\\u0075ll);\n", + "null_new.ts": "new X(n\\u0075ll);\n", + "null_opt.ts": "f?.(n\\u0075ll);\n", + "null_targ.ts": "f(n\\u0075ll);\n", + "this_array.ts": "x = [t\\u0068is];\n", + "this_array2.ts": "x = [1, t\\u0068is];\n", + "this_arrow.ts": "x = () => t\\u0068is;\n", + "this_call.ts": "f(t\\u0068is);\n", + "this_call2.ts": "f(1, t\\u0068is);\n", + "this_new.ts": "new X(t\\u0068is);\n", + "this_opt.ts": "f?.(t\\u0068is);\n", + "this_targ.ts": "f(t\\u0068is);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n", + "void_array.ts": "x = [v\\u006fid 0];\n", + "void_array2.ts": "x = [1, v\\u006fid 0];\n", + "void_arrow.ts": "x = () => v\\u006fid 0;\n", + "void_call.ts": "f(v\\u006fid 0);\n", + "void_call2.ts": "f(1, v\\u006fid 0);\n", + "void_new.ts": "new X(v\\u006fid 0);\n", + "void_opt.ts": "f?.(v\\u006fid 0);\n", + "void_targ.ts": "f(v\\u006fid 0);\n" + } + }, + "83-R03c": { + "files": { + "new_inter.ts": "let x: 1 & n\\u0065w () => Z;\n", + "new_keyof.ts": "let x: keyof n\\u0065w () => Z;\n", + "new_ro.ts": "let x: readonly n\\u0065w () => Z[];\n", + "new_union.ts": "let x: 1 | n\\u0065w () => Z;\n", + "new_union0.ts": "let x: | n\\u0065w () => Z;\n", + "null_call.ts": "f();\n", + "null_call2.ts": "f<1, n\\u0075ll>();\n", + "null_exts.ts": "class C extends A {}\n", + "null_idx.ts": "type X = Y[n\\u0075ll];\n", + "null_iext.ts": "interface I extends A {}\n", + "null_impl.ts": "class C implements A {}\n", + "null_jsx.ts": "x = y as A<[n\\u0075ll]>;\n", + "null_targ.ts": "let x: A;\n", + "null_targ2.ts": "let x: A<1, n\\u0075ll>;\n", + "null_tru.ts": "type X = 1 extends 1 ? n\\u0075ll : 3;\n", + "null_tuple.ts": "let x: [n\\u0075ll];\n", + "null_tuple2.ts": "let x: [1, n\\u0075ll];\n", + "this_call.ts": "f();\n", + "this_call2.ts": "f<1, t\\u0068is>();\n", + "this_exts.ts": "class C extends A {}\n", + "this_idx.ts": "type X = Y[t\\u0068is];\n", + "this_iext.ts": "interface I extends A {}\n", + "this_impl.ts": "class C implements A {}\n", + "this_jsx.ts": "x = y as A<[t\\u0068is]>;\n", + "this_targ.ts": "let x: A;\n", + "this_targ2.ts": "let x: A<1, t\\u0068is>;\n", + "this_tru.ts": "type X = 1 extends 1 ? t\\u0068is : 3;\n", + "this_tuple.ts": "let x: [t\\u0068is];\n", + "this_tuple2.ts": "let x: [1, t\\u0068is];\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n", + "typeof_call.ts": "f();\n", + "typeof_call2.ts": "f<1, t\\u0079peof y>();\n", + "typeof_exts.ts": "class C extends A {}\n", + "typeof_idx.ts": "type X = Y[t\\u0079peof y];\n", + "typeof_iext.ts": "interface I extends A {}\n", + "typeof_impl.ts": "class C implements A {}\n", + "typeof_jsx.ts": "x = y as A<[t\\u0079peof y]>;\n", + "typeof_targ.ts": "let x: A;\n", + "typeof_targ2.ts": "let x: A<1, t\\u0079peof y>;\n", + "typeof_tru.ts": "type X = 1 extends 1 ? t\\u0079peof y : 3;\n", + "typeof_tuple.ts": "let x: [t\\u0079peof y];\n", + "typeof_tuple2.ts": "let x: [1, t\\u0079peof y];\n", + "void_call.ts": "f();\n", + "void_call2.ts": "f<1, v\\u006fid>();\n", + "void_exts.ts": "class C extends A {}\n", + "void_idx.ts": "type X = Y[v\\u006fid];\n", + "void_iext.ts": "interface I extends A {}\n", + "void_impl.ts": "class C implements A {}\n", + "void_jsx.ts": "x = y as A<[v\\u006fid]>;\n", + "void_targ.ts": "let x: A;\n", + "void_targ2.ts": "let x: A<1, v\\u006fid>;\n", + "void_tru.ts": "type X = 1 extends 1 ? v\\u006fid : 3;\n", + "void_tuple.ts": "let x: [v\\u006fid];\n", + "void_tuple2.ts": "let x: [1, v\\u006fid];\n" + } + }, + "83-R10a": { + "files": { + "a.ts": "export {};\ndeclare class B {} interface I {}\nexport class C1 implements (function () { const a: number = \"\"; return a; }) {}\nexport class C7 implements (function () { return this; }) {}\nexport class C9 implements (function (p: any) {}) {}\nexport class C10 implements (function () { const u = 1; }) {}\nexport class C12 implements (class { private p = 1; m(q: any) { const u = 1; } }) {}\nexport class C13 implements ((p: any) => { const u = 1; }) {}\nexport class C14 implements ({ m(p: any) { const u = 1; return this; } }) {}\nexport class C15 implements (function () {}) {}\nexport class C19 implements (function ({ a, b }) {}) {}\nexport class C20 implements (function (...r) {}) {}\nexport interface J1 extends (function (p: any) { const u = 1; return this; }) {}\nexport class D1 extends B, (function (p: any) { const u = 1; return this; }) {}\nexport class D2 extends B extends (function (p: any) { const u = 1; return this; }) {}\nexport class D3 implements I implements (function (p: any) { const u = 1; return this; }) {}\nexport interface J2 extends I extends (function (p: any) { const u = 1; return this; }) {}\nexport class C22 implements (function () { type U = 1; interface V {} enum W {} namespace X {} class Y {} }) {}\nconst sentinel: number = \"\"; sentinel;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"noUnusedLocals\": true, \"noUnusedParameters\": true, \"noImplicitReturns\": true, \"allowUnreachableCode\": false, \"allowUnusedLabels\": false, \"noFallthroughCasesInSwitch\": true } }\n" + } + }, + "83-R11a": { + "files": { + "a01.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? (a): T => { var; } : 1;\nconst sentinel: number = \"\";\n", + "a02.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? (a): T => { declare let; } : 1;\nconst sentinel: number = \"\";\n", + "a03.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? (a): T => { const; } : 1;\nconst sentinel: number = \"\";\n", + "a05.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? (a): T => { var b = 1,; } : 1;\nconst sentinel: number = \"\";\n", + "a07.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? (a): T => { export var; } : 1;\nconst sentinel: number = \"\";\n", + "a08.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? (a): T => function () { var; } : 1;\nconst sentinel: number = \"\";\n", + "a09.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? (a): T => class { m() { var; } } : 1;\nconst sentinel: number = \"\";\n", + "a10.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? (a): T => { var; } : (b): T => { var; };\nconst sentinel: number = \"\";\n", + "a11.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? async (a): T => { var; } : 1;\nconst sentinel: number = \"\";\n", + "a13.ts": "export {}; declare const x: any; type T = any;\nconst v = x ? x ? (a): T => { var; } : 1 : 2;\nconst sentinel: number = \"\";\n", + "c01.ts": "export {}; declare const f: any, x: any;\nconst v = (a): { [(() => { var; return \"x\" })()]: 1 } => x;\nconst sentinel: number = \"\";\n", + "c02.ts": "export {}; declare const f: any, x: any;\nconst v = f<{ [(() => { var; return \"x\" })()]: 1 }>(x);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "83-R11b": { + "files": { + "b01.ts": "const v = x ? (a): T => { f(1 2) } : 1;\n", + "b02.ts": "const v = x ? (a): T => { var b = ; } : 1;\n", + "b03.ts": "const v = x ? (a): T => { if } : 1;\n", + "b04.ts": "const v = x ? (a): T => f(1 2) : 1;\n", + "b05.ts": "const v = x ? (a): T => [1 2] : 1;\n", + "b06.ts": "const v = x ? (a): T => { a b } : 1;\n", + "b10.ts": "const v = x ? (a): T => { € } : 1;\n", + "b11.ts": "const v = x ? (a): T => { function () {} } : 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "83-R13a": { + "files": { + "d01.ts": "function w() { var v = (a, ...) => 1; }\n", + "d03.ts": "var v = (a, ...);\n", + "d07.ts": "var v = (a, ...) => 1;\n", + "d08.ts": "var v = (a, ...,) => 1;\n", + "d09.ts": "var v = (a, ... = 1) => 1;\n", + "d10.ts": "var v = (a, ...: any) => 1;\n", + "d12.ts": "var v = (a, ...1) => 1;\n", + "d15.ts": "var v = (a, ...) => { };\n", + "d16.ts": "f((a, ...) => 1);\n", + "e061.ts": "(a, ...) => 1;\n", + "p061.ts": "async function w(q = (a, ...) => 1) {}\n", + "s061.ts": "var v = (a, ...) => 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "83-R20a": { + "files": { + "a01.ts": "export {}; declare const dec: any;\nasync function f() { interface I { m(@await y: any): void } }\nconst sentinel: number = \"\";\n", + "a02.ts": "export {}; declare const dec: any;\nasync function f() { interface I { (@await y: any): void } }\nconst sentinel: number = \"\";\n", + "a03.ts": "export {}; declare const dec: any;\nasync function f() { interface I { new (@await y: any): void } }\nconst sentinel: number = \"\";\n", + "a11.ts": "export {}; declare const dec: any;\ninterface I { m(@await y: any): void }\nconst sentinel: number = \"\";\n", + "a14.ts": "export {}; declare const dec: any;\nasync function f() { interface I { set s(@await y: any) } }\nconst sentinel: number = \"\";\n", + "a16.ts": "export {}; declare const dec: any;\nasync function f() { interface I { m(a: (@await y: any) => void): void; n(a: new (@await y: any) => void): void } }\nconst sentinel: number = \"\";\n", + "a17.ts": "export {}; declare const dec: any;\nasync function f() { interface I { m(@await.x y: any): void; n(@await() y: any): void } }\nconst sentinel: number = \"\";\n", + "a19.ts": "export {}; declare const dec: any;\nclass K { static { interface I { m(@await y: any): void; n(@dec(await 1) y: any): void } } }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "84-R01": { + "files": { + "b.js": "function h1(@dec x) {}\nfunction h2(export @dec x) {}\nfunction h3(export default @dec x) {}\nclass K { m(a, export @dec y) {} }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true } }\n", + "z.ts": "const sentinel: number = \"\";\n" + } + }, + "84-R02": { + "files": { + "a.ts": "type A = ([...a,]: any);\n", + "b.ts": "type B = ({...a,}: any, b: string);\n", + "c.ts": "type C = string | ([...a,]: any) => void;\n", + "e.ts": "type D = ([...a,]?);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "84-R02b": { + "files": { + "a.ts": "type A = ({#x: a}: any) => void;\ninterface I { m({#x: b}: any): void }\ndeclare function f({#x: c}: any): void;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "84-R02c": { + "files": { + "a.ts": "declare class A {} declare class B {} interface I {}\ntype T1 = ({a = class extends A, B {}}: any) => void;\ntype T2 = ({a = class extends A extends B {}}: any) => void;\ntype T3 = ({a = class implements I extends A {}}: any) => void;\ntype T4 = ({a = class <> {}}: any) => void;\ntype T5 = ({a = class { m<>() {} }}: any) => void;\ntype T6 = ({a = (public a) => 1}: any) => void;\ntype OK = ({a = class extends A, B {}}: any) => void;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "84-R03": { + "files": { + "a.js": "/** @type {NS.A.} */ let y1 = 1;\n/** @type {Array} */ let y2 = [1];\n/** @type {import(\"./m\").M.} */ let y3 = 1;\n/** @type {typeof globalThis.} */ let y4 = 1;\n/** @type {typeof p.} */ let y5 = 1;\n/** @type {number} */ const sentinel = \"\";\n", + "m.d.ts": "export namespace M { interface X {} }\n", + "n.d.ts": "declare namespace NS { interface A { a: number } }\ndeclare class P { private \"\": number }\ndeclare const p: P;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "84-R04": { + "files": { + "a.js": "const a = { b: { c: 1 } };\n/** @type {typeof nope..b} */ let x1 = 1;\n/** @type {typeof a.nope..b} */ let x2 = 1;\n/** @type {typeof em..z} */ let x3 = 2;\n/** @type {number} */ const sentinel = \"\";\n", + "n.d.ts": "declare const em: { \"\": { z: 1 } };\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "84-R06": { + "files": { + "a.ts": "declare function g(...a: boolean[]): void;\ndeclare const x: unknown, b: number, c: number, d: number, an: any;\ndeclare let n: number;\ng(x as number < b, c > (d));\ng(x satisfies unknown as number < b, c > (d));\nconst t = [x as number < b, c > (d)];\nconst u = x as any < b > (an);\ng(n++ < b, c > (d));\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "84-R06b": { + "files": { + "a.ts": "declare function f(): void;\nf<<>() => void>();\nconst q = f<<>() => void>;\nf() => void>();\nf<{ m<>(): void }>();\nlet ok: <>() => void;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "84-R08c": { + "files": { + "a.ts": "declare function dec(...x: any[]): any;\n@dec import(\"./m\");\nexport @dec import(\"./m\");\nfunction f() { @dec import(\"./m\"); }\nconst sentinel: number = \"\";\n", + "m.ts": "export {};\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "84-R08d": { + "files": { + "a.ts": "declare function dec2(...x: any[]): any;\n@dec2 import.meta;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "85-R03a": { + "files": { + "a1.js": "class C { p = [this.p, module]; }\nmodule.exports = C;\n", + "a2.js": "class C { static p = [C.p, exports]; }\nexports.C = C;\n", + "a3.js": "function f() {}\nf.p = [f.p, module];\nmodule.exports = f;\n", + "a4.js": "exports.a = [exports.a, module];\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n", + "zz.ts": "export {};\nconst sentinel: number = \"\";\n" + } + }, + "85-R03b": { + "files": { + "f.js": "var v = mk().x;\nfunction mk() { return new C(); }\nclass C { get x() { return [module, this.x]; } }\nv.nope;\nmodule.exports = C;\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": false, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "85-R03c": { + "files": { + "f.js": "var p = r;\nvar r = [module, r, exports];\nexports.zz = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n", + "zz.ts": "export {};\nconst sentinel: number = \"\";\n" + } + }, + "85-R03f": { + "files": { + "a.js": "var p = r;\nvar r = [r, require(\"./b\").y];\nexports.k = 1;\n/** @type {never} */ var tp = p;\n/** @type {number} */\nconst sentinel = \"\";\n", + "b.js": "exports.y = exports.z;\nexports.z = 1;\nvar p = r;\nvar r = [r, exports];\n/** @type {never} */ var tp = p;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "85-R03g": { + "files": { + "a.js": "var p = r;\nvar r = [r, exports];\nexports.y = exports.z;\nexports.z = 1;\n/** @type {never} */ var tp = p;\n", + "b.js": "var q = s;\nvar s = [s, require(\"./a\").y, exports];\nexports.k = 1;\n/** @type {never} */ var tq = q;\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "85-R16a": { + "files": { + "a.ts": "import { p } from \"./m\";\nexport const y = p;\nconst t: never = y;\nconst sentinel: number = \"\";\n", + "m.ts": "import { y } from \"./a\";\ninterface B { b: T }\ninterface V extends B { p: number }\ndeclare const v: V;\nexport = v;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" }, \"files\": [\"a.ts\", \"m.ts\"] }\n" + } + }, + "85-R16b": { + "files": { + "a.ts": "import { p } from \"./m\";\nexport const y = p;\nconst t: never = y;\nconst sentinel: number = \"\";\n", + "m.ts": "import { y } from \"./a\";\ninterface B { b: T }\ninterface V extends B { p: number }\ndeclare const v: V;\nexport = v;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" }, \"files\": [\"m.ts\", \"a.ts\"] }\n" + } + }, + "85-R16c": { + "files": { + "a.ts": "import { p } from \"./m\";\nexport function g() { return [p]; }\nconst t: never = g;\nconst sentinel: number = \"\";\n", + "m.ts": "import { g } from \"./a\";\nconst v = { get p() { return g(); } };\nexport = v;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" }, \"files\": [\"a.ts\", \"m.ts\"] }\n" + } + }, + "85-R18a": { + "files": { + "a.ts": "import { Event, Response, Request, URL } from \"./t\";\nimport type { Headers } from \"./t\";\nexport const e = new Event(\"x\");\nexport const r = new Response();\nexport const h = new Headers();\nexport const u = new URL(\"http://x\");\nexport function f(q: Request) { return new Request(\"http://x\"); }\nexport const sentinel: number = \"\";\n", + "t.ts": "export interface Event { mine: 1 }\nexport type Response = { r: 1 };\nexport interface Request { q: 1 }\nexport interface Headers { h: 1 }\nexport namespace URL { export type Part = string }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"dom\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"noUnusedLocals\": true } }\n" + } + }, + "86-R02a": { + "files": { + "a.ts": "Document.a = 2;\nconst sentinel: number = \"\";\n", + "node_modules/@typescript/lib-dom/index.js": "var Document = { a: 1 };\n/** @type {number} */ var bad = \"\";\nfunction helper(x) { return x; }\nclass Win { constructor() { this.p = 1; } }\n", + "node_modules/@typescript/lib-dom/package.json": "{\"name\":\"@typescript/lib-dom\",\"version\":\"1.0.0\",\"main\":\"index.js\"}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"dom\"], \"libReplacement\": true, \"allowJs\": true, \"checkJs\": true, \"skipLibCheck\": true }, \"files\": [\"a.ts\"] }\n" + } + }, + "86-R03a": { + "files": { + "a.d.ts": "declare namespace f { interface x { j: 1 } }\n", + "b.ts": "function f() {}\nf.x = \"s\";\nconst p: number = f.x;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] }, \"files\": [\"a.d.ts\", \"b.ts\"] }\n" + } + }, + "86-R03b": { + "files": { + "a.d.ts": "declare namespace C { interface x { j: 1 } }\n", + "b.js": "class C {}\nC.x = \"s\";\n", + "c.ts": "const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true }, \"files\": [\"a.d.ts\", \"b.js\", \"c.ts\"] }\n" + } + }, + "86-R04a": { + "files": { + "a.ts": "const sentinel: number = \"\";\n", + "node_modules/@typescript/lib-dom/index.js": "module.exports = {}\n", + "node_modules/@typescript/lib-dom/package.json": "{\"name\":\"@typescript/lib-dom\",\"version\":\"1.0.0\",\"main\":\"index.js\"}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"dom\"], \"libReplacement\": true }, \"files\": [\"a.ts\", \"node_modules/@typescript/lib-dom/index.js\"] }\n" + } + }, + "86-R08": { + "files": { + "a.ts": "import { vx, px } from \"x\"; import { vy } from \"y\";\nconst n1: null = vx; const n2: null = px; const n3: null = vy;\nconst sentinel: number = \"\";\n", + "node_modules/deep/index.js": "exports.d = 1;\n", + "node_modules/deep/package.json": "{\"name\":\"deep\",\"version\":\"1.0.0\",\"main\":\"index.js\"}\n", + "node_modules/x/index.js": "const m = require(\"mid\"); const p = require(\"p\"); exports.vx = m.v; exports.px = p.pv;\n", + "node_modules/x/node_modules/mid/index.js": "const d = require(\"deep\"); exports.v = d.d;\n", + "node_modules/x/node_modules/mid/package.json": "{\"name\":\"mid\",\"version\":\"1.0.0\",\"main\":\"index.js\"}\n", + "node_modules/x/node_modules/p/index.js": "const m = require(\"mid\"); exports.pv = m.v;\n", + "node_modules/x/node_modules/p/package.json": "{\"name\":\"p\",\"version\":\"1.0.0\",\"main\":\"index.js\"}\n", + "node_modules/x/package.json": "{\"name\":\"x\",\"version\":\"1.0.0\",\"main\":\"index.js\"}\n", + "node_modules/y/index.js": "const p = require(\"p\"); exports.vy = p.pv;\n", + "node_modules/y/node_modules/p/index.js": "const m = require(\"mid\"); exports.pv = m.v;\n", + "node_modules/y/node_modules/p/package.json": "{\"name\":\"p\",\"version\":\"1.0.0\",\"main\":\"index.js\"}\n", + "node_modules/y/package.json": "{\"name\":\"y\",\"version\":\"1.0.0\",\"main\":\"index.js\"}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\", \"allowJs\": true, \"maxNodeModuleJsDepth\": 3 }, \"files\": [\"a.ts\"] }\n" + } + }, + "86-R10a": { + "files": { + "a.ts": "import * as sx from \"./x\";\nexport { sx };\n", + "b.ts": "import * as sx from \"./x\";\nexport { sx };\n", + "index.ts": "export * from \"./a\";\nexport * from \"./b\";\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"index.ts\"] }\n", + "x.ts": "export const X = 1;\nexport default 1;\n" + } + }, + "86-R11a": { + "files": { + "a.ts": "document.title = 2; const d: Document = { title: 3 };\nconst sentinel: number = \"\";\n", + "node_modules/@typescript/lib-dom/index.ts": "interface Document { title: string }\nvar document: Document = { title: 1 };\n", + "node_modules/@typescript/lib-dom/package.json": "{\"name\":\"@typescript/lib-dom\",\"version\":\"1.0.0\",\"types\":\"index.ts\"}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"dom\"], \"libReplacement\": true, \"skipLibCheck\": true }, \"files\": [\"a.ts\"] }\n" + } + }, + "86-R11b": { + "files": { + "a.ts": "document.title = 2; const d: Document = { title: 3 };\nconst sentinel: number = \"\";\n", + "node_modules/@typescript/lib-dom/index.ts": "interface Document { title: string }\nvar document: Document = { title: 1 };\n", + "node_modules/@typescript/lib-dom/package.json": "{\"name\":\"@typescript/lib-dom\",\"version\":\"1.0.0\",\"types\":\"index.ts\"}\n", + "out/a.d.ts": "declare const d: Document;\ndeclare const sentinel: number;\n", + "out/a.js": "\"use strict\";\ndocument.title = 2;\nconst d = { title: 3 };\nconst sentinel = \"\";\n", + "out/node_modules/@typescript/lib-dom/index.d.ts": "interface Document {\n title: string;\n}\ndeclare var document: Document;\n", + "out/node_modules/@typescript/lib-dom/index.js": "\"use strict\";\nvar document = { title: 1 };\n", + "out/tsconfig.tsbuildinfo": "{\"version\":\"7.0.2\",\"errors\":true,\"root\":[59],\"packageJsons\":[\"../../../../../../package.json\",\"../node_modules/@typescript/lib-dom/package.json\"],\"missingPackageJsons\":[\"../../../../../../node_modules/@typescript/lib-decorators/legacy/package.json\",\"../../../../../../node_modules/@typescript/lib-decorators/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/collection/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/core/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/generator/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/iterable/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/promise/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/proxy/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/reflect/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/symbol-wellknown/package.json\",\"../../../../../../node_modules/@typescript/lib-es2015/symbol/package.json\",\"../../../../../../node_modules/@typescript/lib-es2016/array-include/package.json\",\"../../../../../../node_modules/@typescript/lib-es2016/intl/package.json\",\"../../../../../../node_modules/@typescript/lib-es2016/package.json\",\"../../../../../../node_modules/@typescript/lib-es2017/arraybuffer/package.json\",\"../../../../../../node_modules/@typescript/lib-es2017/date/package.json\",\"../../../../../../node_modules/@typescript/lib-es2017/intl/package.json\",\"../../../../../../node_modules/@typescript/lib-es2017/object/package.json\",\"../../../../../../node_modules/@typescript/lib-es2017/package.json\",\"../../../../../../node_modules/@typescript/lib-es2017/sharedmemory/package.json\",\"../../../../../../node_modules/@typescript/lib-es2017/string/package.json\",\"../../../../../../node_modules/@typescript/lib-es2017/typedarrays/package.json\",\"../../../../../../node_modules/@typescript/lib-es2018/asyncgenerator/package.json\",\"../../../../../../node_modules/@typescript/lib-es2018/asynciterable/package.json\",\"../../../../../../node_modules/@typescript/lib-es2018/intl/package.json\",\"../../../../../../node_modules/@typescript/lib-es2018/package.json\",\"../../../../../../node_modules/@typescript/lib-es2018/promise/package.json\",\"../../../../../../node_modules/@typescript/lib-es2018/regexp/package.json\",\"../../../../../../node_modules/@typescript/lib-es2019/array/package.json\",\"../../../../../../node_modules/@typescript/lib-es2019/intl/package.json\",\"../../../../../../node_modules/@typescript/lib-es2019/object/package.json\",\"../../../../../../node_modules/@typescript/lib-es2019/package.json\",\"../../../../../../node_modules/@typescript/lib-es2019/string/package.json\",\"../../../../../../node_modules/@typescript/lib-es2019/symbol/package.json\",\"../../../../../../node_modules/@typescript/lib-es2020/bigint/package.json\",\"../../../../../../node_modules/@typescript/lib-es2020/date/package.json\",\"../../../../../../node_modules/@typescript/lib-es2020/intl/package.json\",\"../../../../../../node_modules/@typescript/lib-es2020/number/package.json\",\"../../../../../../node_modules/@typescript/lib-es2020/package.json\",\"../../../../../../node_modules/@typescript/lib-es2020/promise/package.json\",\"../../../../../../node_modules/@typescript/lib-es2020/sharedmemory/package.json\",\"../../../../../../node_modules/@typescript/lib-es2020/string/package.json\",\"../../../../../../node_modules/@typescript/lib-es2020/symbol-wellknown/package.json\",\"../../../../../../node_modules/@typescript/lib-es2021/intl/package.json\",\"../../../../../../node_modules/@typescript/lib-es2021/package.json\",\"../../../../../../node_modules/@typescript/lib-es2021/promise/package.json\",\"../../../../../../node_modules/@typescript/lib-es2021/string/package.json\",\"../../../../../../node_modules/@typescript/lib-es2021/weakref/package.json\",\"../../../../../../node_modules/@typescript/lib-es2022/array/package.json\",\"../../../../../../node_modules/@typescript/lib-es2022/error/package.json\",\"../../../../../../node_modules/@typescript/lib-es2022/intl/package.json\",\"../../../../../../node_modules/@typescript/lib-es2022/object/package.json\",\"../../../../../../node_modules/@typescript/lib-es2022/package.json\",\"../../../../../../node_modules/@typescript/lib-es2022/regexp/package.json\",\"../../../../../../node_modules/@typescript/lib-es2022/string/package.json\",\"../../../../../../node_modules/@typescript/lib-es5/package.json\",\"../node_modules/@typescript/lib-decorators/legacy/package.json\",\"../node_modules/@typescript/lib-decorators/package.json\",\"../node_modules/@typescript/lib-es2015/collection/package.json\",\"../node_modules/@typescript/lib-es2015/core/package.json\",\"../node_modules/@typescript/lib-es2015/generator/package.json\",\"../node_modules/@typescript/lib-es2015/iterable/package.json\",\"../node_modules/@typescript/lib-es2015/package.json\",\"../node_modules/@typescript/lib-es2015/promise/package.json\",\"../node_modules/@typescript/lib-es2015/proxy/package.json\",\"../node_modules/@typescript/lib-es2015/reflect/package.json\",\"../node_modules/@typescript/lib-es2015/symbol-wellknown/package.json\",\"../node_modules/@typescript/lib-es2015/symbol/package.json\",\"../node_modules/@typescript/lib-es2016/array-include/package.json\",\"../node_modules/@typescript/lib-es2016/intl/package.json\",\"../node_modules/@typescript/lib-es2016/package.json\",\"../node_modules/@typescript/lib-es2017/arraybuffer/package.json\",\"../node_modules/@typescript/lib-es2017/date/package.json\",\"../node_modules/@typescript/lib-es2017/intl/package.json\",\"../node_modules/@typescript/lib-es2017/object/package.json\",\"../node_modules/@typescript/lib-es2017/package.json\",\"../node_modules/@typescript/lib-es2017/sharedmemory/package.json\",\"../node_modules/@typescript/lib-es2017/string/package.json\",\"../node_modules/@typescript/lib-es2017/typedarrays/package.json\",\"../node_modules/@typescript/lib-es2018/asyncgenerator/package.json\",\"../node_modules/@typescript/lib-es2018/asynciterable/package.json\",\"../node_modules/@typescript/lib-es2018/intl/package.json\",\"../node_modules/@typescript/lib-es2018/package.json\",\"../node_modules/@typescript/lib-es2018/promise/package.json\",\"../node_modules/@typescript/lib-es2018/regexp/package.json\",\"../node_modules/@typescript/lib-es2019/array/package.json\",\"../node_modules/@typescript/lib-es2019/intl/package.json\",\"../node_modules/@typescript/lib-es2019/object/package.json\",\"../node_modules/@typescript/lib-es2019/package.json\",\"../node_modules/@typescript/lib-es2019/string/package.json\",\"../node_modules/@typescript/lib-es2019/symbol/package.json\",\"../node_modules/@typescript/lib-es2020/bigint/package.json\",\"../node_modules/@typescript/lib-es2020/date/package.json\",\"../node_modules/@typescript/lib-es2020/intl/package.json\",\"../node_modules/@typescript/lib-es2020/number/package.json\",\"../node_modules/@typescript/lib-es2020/package.json\",\"../node_modules/@typescript/lib-es2020/promise/package.json\",\"../node_modules/@typescript/lib-es2020/sharedmemory/package.json\",\"../node_modules/@typescript/lib-es2020/string/package.json\",\"../node_modules/@typescript/lib-es2020/symbol-wellknown/package.json\",\"../node_modules/@typescript/lib-es2021/intl/package.json\",\"../node_modules/@typescript/lib-es2021/package.json\",\"../node_modules/@typescript/lib-es2021/promise/package.json\",\"../node_modules/@typescript/lib-es2021/string/package.json\",\"../node_modules/@typescript/lib-es2021/weakref/package.json\",\"../node_modules/@typescript/lib-es2022/array/package.json\",\"../node_modules/@typescript/lib-es2022/error/package.json\",\"../node_modules/@typescript/lib-es2022/intl/package.json\",\"../node_modules/@typescript/lib-es2022/object/package.json\",\"../node_modules/@typescript/lib-es2022/package.json\",\"../node_modules/@typescript/lib-es2022/regexp/package.json\",\"../node_modules/@typescript/lib-es2022/string/package.json\",\"../node_modules/@typescript/lib-es5/package.json\"],\"fileNames\":[\"lib.es5.d.ts\",\"lib.es2015.d.ts\",\"lib.es2016.d.ts\",\"lib.es2017.d.ts\",\"lib.es2018.d.ts\",\"lib.es2019.d.ts\",\"lib.es2020.d.ts\",\"lib.es2021.d.ts\",\"lib.es2022.d.ts\",\"lib.es2015.core.d.ts\",\"lib.es2015.collection.d.ts\",\"lib.es2015.generator.d.ts\",\"lib.es2015.iterable.d.ts\",\"lib.es2015.promise.d.ts\",\"lib.es2015.proxy.d.ts\",\"lib.es2015.reflect.d.ts\",\"lib.es2015.symbol.d.ts\",\"lib.es2015.symbol.wellknown.d.ts\",\"lib.es2016.array.include.d.ts\",\"lib.es2016.intl.d.ts\",\"lib.es2017.arraybuffer.d.ts\",\"lib.es2017.date.d.ts\",\"lib.es2017.object.d.ts\",\"lib.es2017.sharedmemory.d.ts\",\"lib.es2017.string.d.ts\",\"lib.es2017.intl.d.ts\",\"lib.es2017.typedarrays.d.ts\",\"lib.es2018.asyncgenerator.d.ts\",\"lib.es2018.asynciterable.d.ts\",\"lib.es2018.intl.d.ts\",\"lib.es2018.promise.d.ts\",\"lib.es2018.regexp.d.ts\",\"lib.es2019.array.d.ts\",\"lib.es2019.object.d.ts\",\"lib.es2019.string.d.ts\",\"lib.es2019.symbol.d.ts\",\"lib.es2019.intl.d.ts\",\"lib.es2020.bigint.d.ts\",\"lib.es2020.date.d.ts\",\"lib.es2020.promise.d.ts\",\"lib.es2020.sharedmemory.d.ts\",\"lib.es2020.string.d.ts\",\"lib.es2020.symbol.wellknown.d.ts\",\"lib.es2020.intl.d.ts\",\"lib.es2020.number.d.ts\",\"lib.es2021.promise.d.ts\",\"lib.es2021.string.d.ts\",\"lib.es2021.weakref.d.ts\",\"lib.es2021.intl.d.ts\",\"lib.es2022.array.d.ts\",\"lib.es2022.error.d.ts\",\"lib.es2022.intl.d.ts\",\"lib.es2022.object.d.ts\",\"lib.es2022.string.d.ts\",\"lib.es2022.regexp.d.ts\",\"lib.decorators.d.ts\",\"lib.decorators.legacy.d.ts\",\"../node_modules/@typescript/lib-dom/index.ts\",\"../a.ts\"],\"fileInfos\":[{\"version\":\"16934abaab7026ac114da441aabea1a0\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},\"d4306fb2e47f74835e8674ffac07d76f\",\"e437c5c1302869326c3bb93da85bbbcf\",\"e4324975a566567b21d350615f1fc6ac\",\"333b1b9a2a9ac3b8497dba5c63b5ba50\",\"6cffacd662b6eb5fa7a36aa2ea366bfa\",\"b4c34f9c23304dbef2d23698637ed638\",\"e5cb86a5fc491796ecd1d2dd348d208f\",\"feb6c6fb19cdb246a5d8acb36a6901c7\",{\"version\":\"926204c28cd3d073865348473ae28d2e\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"f25e42c801b2cb3cf2b39792006a9beb\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"6344b55f26a4e81d9608777dbfb877dd\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"3c0ed28e53d3695b363e256ec1c023fd\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"4c2761daba7f17141c25baa0821ac5da\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"b87656acabd63e69379ff6ffcfe52fc7\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"597469522da047a5af5222cc6989f405\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"1708ea4d34dc37fadadc63ca01127e80\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"55d97a8c6fbf34a30450a7b1e5f7a298\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"0ee05eb59426d33e374226d8dcfa708b\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"e347c14030993906efcfbb88915b6a05\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"b0231263857c9b6a03641acdc9280ceb\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"3b15c4a83b598cacb4067676e6f0abed\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"b417d97b7934cef63b1889abec0bbfbf\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"09a6cf4032ebba60ce22a501e663f881\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"2b056277dd138e8f5650fc04e20eaa8d\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"e22cc07e3f3cc242ba52fa3f8ea1fc58\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"2c45da767a1bfbb220848df1bc4029e4\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"b44c3e0fbaf2130cdcf6ac38b120ffa1\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"b612fb5cf8e5d964b92063a75207632a\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"02705151a5e1551b9162a9ed8ab763f7\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"41025e398be9215d32e4337335da8f0b\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"52684c2b1f353a5538e4f275182a54cd\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"6dedb6a4f90d1df3a6fbe5693e44886c\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"ca3f36fe3562c07e0f0d71c2bebd3f6d\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"409974d6129befbb8226ddd1c6558568\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"4d9cfde2a1ae1b4925f1f9bc10848e5d\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"7e1daecc66dd564144e3bb1a0266b5fd\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"a8e1d9bb35fd0637f2f9fd2b2a54f2ec\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"4f168501772a6543182765bfd5f2fbfe\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"a19c80aad1b2162103496f5ba293a732\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"b69afa63cd5d059851c78adb2856ee09\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"ae2fc5d954e9b0f5feee3d481b953c27\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"1cfd3091a071d8b6feec15277643bafe\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"1da2c1f258970fd3cc91184f69e91a9d\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"a0d87491913d843139e0c993650a3235\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"4ef72aa378127e7b7abba915b0110b1e\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"3ec74c6a7d4463f0254db3a74cf75646\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"84c2bdfa470d075526cce6322d81b0b6\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"0b3844c2b8c73e4e1ab91431411cad11\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"4fc71cf4a15b8d99675a31df77f26e07\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"d1b49564ddaeca3df5b6dbae925d2242\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"6a25be566d60ccfc2d6e8b7bfdeefa83\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"8a20e27646985dfd58c57ca6566553dd\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"9969f02ad3cdcbf4f709405cda44167f\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"9c9be4792a7a4f42c15ae7360bf28779\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"f64453cbf9671f28158677fa5c43967a\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"33f317af5428801f944a478d2c1e38e5\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"c1082d3c5181407a0ccdc07eabbb5384\",\"signature\":\"9aae88d9460bb9b9ef4bf77a8d372078\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1},{\"version\":\"192cbd18f154a196aa3e4ab88f6fbb84\",\"signature\":\"4585327b495fdf3971d53afd83b77e20\",\"affectsGlobalScope\":true,\"impliedNodeFormat\":1}],\"options\":{\"composite\":true,\"outDir\":\"./\",\"strict\":true},\"semanticDiagnosticsPerFile\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59],\"latestChangedDtsFile\":\"./a.d.ts\"}", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"types\": [], \"lib\": [\"es2022\", \"dom\"], \"libReplacement\": true, \"composite\": true, \"outDir\": \"out\" }, \"files\": [\"a.ts\"] }\n" + } + }, + "86-R11c": { + "files": { + "a.ts": "doc.a = \"\";\nconst sentinel: number = \"\";\n", + "node_modules/@typescript/lib-dom/index.d.ts": "import { X } from \"./other\";\ndeclare global { var doc: X }\n", + "node_modules/@typescript/lib-dom/other.d.ts": "export interface X { a: number }\n", + "node_modules/@typescript/lib-dom/package.json": "{\"name\":\"@typescript/lib-dom\",\"version\":\"1.0.0\",\"type\":\"module\",\"types\":\"index.d.ts\"}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"dom\"], \"libReplacement\": true, \"module\": \"nodenext\" }, \"files\": [\"a.ts\"] }\n" + } + }, + "86-R13b": { + "files": { + "a.ts": "Foob;\nexport {};\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" } }\n", + "u.d.ts": "export as namespace Foob;\nexport = nothing;\n" + } + }, + "86-R16": { + "files": { + "d.ts": "export {};\n{ declare module \"./m\" { interface InBlock { a: 1 } } }\ndeclare module \"./m\" { interface AfterBlock { a: 1 } }\n", + "e.ts": "export {};\ndeclare module \"./m\" { interface BeforeBlock { a: 1 } }\nif (1) { declare module \"./m\" { interface InBlock2 { a: 1 } } }\n", + "m.ts": "export interface Own { o: 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"m.ts\", \"d.ts\", \"e.ts\", \"use.ts\"] }\n", + "use.ts": "import { Own, InBlock, AfterBlock, BeforeBlock, InBlock2 } from \"./m\";\nconst sentinel: number = \"\";\n" + } + }, + "86-R20a": { + "files": { + "a.ts": "declare const i0: I0;\nconst j0: J0 = i0;\ndeclare const i70: I70;\nconst j70: J70 = i70;\ntype TC = I70 extends J70 ? 1 : 2;\nconst tc: TC = 0;\ntype TD = I69 extends J69 ? 1 : 2;\nconst td: TD = 0;\nconst sentinel: number = \"\";\n", + "t.d.ts": "interface I0 { n: I1 }\ninterface I1 { n: I2 }\ninterface I2 { n: I3 }\ninterface I3 { n: I4 }\ninterface I4 { n: I5 }\ninterface I5 { n: I6 }\ninterface I6 { n: I7 }\ninterface I7 { n: I8 }\ninterface I8 { n: I9 }\ninterface I9 { n: I10 }\ninterface I10 { n: I11 }\ninterface I11 { n: I12 }\ninterface I12 { n: I13 }\ninterface I13 { n: I14 }\ninterface I14 { n: I15 }\ninterface I15 { n: I16 }\ninterface I16 { n: I17 }\ninterface I17 { n: I18 }\ninterface I18 { n: I19 }\ninterface I19 { n: I20 }\ninterface I20 { n: I21 }\ninterface I21 { n: I22 }\ninterface I22 { n: I23 }\ninterface I23 { n: I24 }\ninterface I24 { n: I25 }\ninterface I25 { n: I26 }\ninterface I26 { n: I27 }\ninterface I27 { n: I28 }\ninterface I28 { n: I29 }\ninterface I29 { n: I30 }\ninterface I30 { n: I31 }\ninterface I31 { n: I32 }\ninterface I32 { n: I33 }\ninterface I33 { n: I34 }\ninterface I34 { n: I35 }\ninterface I35 { n: I36 }\ninterface I36 { n: I37 }\ninterface I37 { n: I38 }\ninterface I38 { n: I39 }\ninterface I39 { n: I40 }\ninterface I40 { n: I41 }\ninterface I41 { n: I42 }\ninterface I42 { n: I43 }\ninterface I43 { n: I44 }\ninterface I44 { n: I45 }\ninterface I45 { n: I46 }\ninterface I46 { n: I47 }\ninterface I47 { n: I48 }\ninterface I48 { n: I49 }\ninterface I49 { n: I50 }\ninterface I50 { n: I51 }\ninterface I51 { n: I52 }\ninterface I52 { n: I53 }\ninterface I53 { n: I54 }\ninterface I54 { n: I55 }\ninterface I55 { n: I56 }\ninterface I56 { n: I57 }\ninterface I57 { n: I58 }\ninterface I58 { n: I59 }\ninterface I59 { n: I60 }\ninterface I60 { n: I61 }\ninterface I61 { n: I62 }\ninterface I62 { n: I63 }\ninterface I63 { n: I64 }\ninterface I64 { n: I65 }\ninterface I65 { n: I66 }\ninterface I66 { n: I67 }\ninterface I67 { n: I68 }\ninterface I68 { n: I69 }\ninterface I69 { n: I70 }\ninterface I70 { n: I71 }\ninterface I71 { n: I72 }\ninterface I72 { n: I73 }\ninterface I73 { n: I74 }\ninterface I74 { n: I75 }\ninterface I75 { n: I76 }\ninterface I76 { n: I77 }\ninterface I77 { n: I78 }\ninterface I78 { n: I79 }\ninterface I79 { n: I80 }\ninterface I80 { n: I81 }\ninterface I81 { n: I82 }\ninterface I82 { n: I83 }\ninterface I83 { n: I84 }\ninterface I84 { n: I85 }\ninterface I85 { n: I86 }\ninterface I86 { n: I87 }\ninterface I87 { n: I88 }\ninterface I88 { n: I89 }\ninterface I89 { n: I90 }\ninterface I90 { n: I91 }\ninterface I91 { n: I92 }\ninterface I92 { n: I93 }\ninterface I93 { n: I94 }\ninterface I94 { n: I95 }\ninterface I95 { n: I96 }\ninterface I96 { n: I97 }\ninterface I97 { n: I98 }\ninterface I98 { n: I99 }\ninterface I99 { n: I100 }\ninterface I100 { v: 1 }\ninterface J0 { n: J1 }\ninterface J1 { n: J2 }\ninterface J2 { n: J3 }\ninterface J3 { n: J4 }\ninterface J4 { n: J5 }\ninterface J5 { n: J6 }\ninterface J6 { n: J7 }\ninterface J7 { n: J8 }\ninterface J8 { n: J9 }\ninterface J9 { n: J10 }\ninterface J10 { n: J11 }\ninterface J11 { n: J12 }\ninterface J12 { n: J13 }\ninterface J13 { n: J14 }\ninterface J14 { n: J15 }\ninterface J15 { n: J16 }\ninterface J16 { n: J17 }\ninterface J17 { n: J18 }\ninterface J18 { n: J19 }\ninterface J19 { n: J20 }\ninterface J20 { n: J21 }\ninterface J21 { n: J22 }\ninterface J22 { n: J23 }\ninterface J23 { n: J24 }\ninterface J24 { n: J25 }\ninterface J25 { n: J26 }\ninterface J26 { n: J27 }\ninterface J27 { n: J28 }\ninterface J28 { n: J29 }\ninterface J29 { n: J30 }\ninterface J30 { n: J31 }\ninterface J31 { n: J32 }\ninterface J32 { n: J33 }\ninterface J33 { n: J34 }\ninterface J34 { n: J35 }\ninterface J35 { n: J36 }\ninterface J36 { n: J37 }\ninterface J37 { n: J38 }\ninterface J38 { n: J39 }\ninterface J39 { n: J40 }\ninterface J40 { n: J41 }\ninterface J41 { n: J42 }\ninterface J42 { n: J43 }\ninterface J43 { n: J44 }\ninterface J44 { n: J45 }\ninterface J45 { n: J46 }\ninterface J46 { n: J47 }\ninterface J47 { n: J48 }\ninterface J48 { n: J49 }\ninterface J49 { n: J50 }\ninterface J50 { n: J51 }\ninterface J51 { n: J52 }\ninterface J52 { n: J53 }\ninterface J53 { n: J54 }\ninterface J54 { n: J55 }\ninterface J55 { n: J56 }\ninterface J56 { n: J57 }\ninterface J57 { n: J58 }\ninterface J58 { n: J59 }\ninterface J59 { n: J60 }\ninterface J60 { n: J61 }\ninterface J61 { n: J62 }\ninterface J62 { n: J63 }\ninterface J63 { n: J64 }\ninterface J64 { n: J65 }\ninterface J65 { n: J66 }\ninterface J66 { n: J67 }\ninterface J67 { n: J68 }\ninterface J68 { n: J69 }\ninterface J69 { n: J70 }\ninterface J70 { n: J71 }\ninterface J71 { n: J72 }\ninterface J72 { n: J73 }\ninterface J73 { n: J74 }\ninterface J74 { n: J75 }\ninterface J75 { n: J76 }\ninterface J76 { n: J77 }\ninterface J77 { n: J78 }\ninterface J78 { n: J79 }\ninterface J79 { n: J80 }\ninterface J80 { n: J81 }\ninterface J81 { n: J82 }\ninterface J82 { n: J83 }\ninterface J83 { n: J84 }\ninterface J84 { n: J85 }\ninterface J85 { n: J86 }\ninterface J86 { n: J87 }\ninterface J87 { n: J88 }\ninterface J88 { n: J89 }\ninterface J89 { n: J90 }\ninterface J90 { n: J91 }\ninterface J91 { n: J92 }\ninterface J92 { n: J93 }\ninterface J93 { n: J94 }\ninterface J94 { n: J95 }\ninterface J95 { n: J96 }\ninterface J96 { n: J97 }\ninterface J97 { n: J98 }\ninterface J98 { n: J99 }\ninterface J99 { n: J100 }\ninterface J100 { v: 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] }, \"files\": [\"t.d.ts\", \"a.ts\"] }\n" + } + }, + "87-R01a": { + "files": { + "a.ts": "type D = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype Mk = K extends any ? { a: K } : never;\ntype S = Mk<`s${D}${D}${D}`>;\ntype T = Mk<`t${D}${D}${D}` | `u${D}${D}${D}` | `v${D}${D}`> | { a: string };\ndeclare let s: S; declare let t: T; declare const c: boolean;\nfunction h(): S;\nfunction h(): T { return t; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R01b": { + "files": { + "a.ts": "type D = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype Mk = K extends any ? { a: K } : never;\ntype S = Mk<`s${D}${D}${D}`>;\ntype T = Mk<`t${D}${D}${D}` | `u${D}${D}${D}` | `v${D}${D}`> | { a: string };\ndeclare let s: S; declare let t: T; declare const c: boolean;\nclass K {\n h(a: T): void;\n h(a: S): void {}\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, + "87-R01c": { + "files": { + "a.ts": "type D = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype Mk = K extends any ? { a: K } : never;\ntype S = Mk<`s${D}${D}${D}`>;\ntype T = Mk<`t${D}${D}${D}` | `u${D}${D}${D}` | `v${D}${D}`> | { a: string };\ndeclare let s: S; declare let t: T; declare const c: boolean;\n[t] = [s];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, + "87-R01e": { + "files": { + "a.ts": "type D = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype Mk = K extends any ? { a: K } : never;\ntype S = Mk<`s${D}${D}${D}`>;\ntype T = Mk<`t${D}${D}${D}` | `u${D}${D}${D}` | `v${D}${D}`> | { a: string };\ndeclare let s: S; declare let t: T; declare const c: boolean;\nclass G { v!: X }\nclass H extends G {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R01f": { + "files": { + "a.ts": "type D = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype Mk = K extends any ? { a: K } : never;\ntype S = Mk<`s${D}${D}${D}`>;\ntype T = Mk<`t${D}${D}${D}` | `u${D}${D}${D}` | `v${D}${D}`> | { a: string };\ndeclare let s: S; declare let t: T; declare const c: boolean;\nclass A { static p: T }\nclass B extends A { static p: S }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, + "87-R01j": { + "files": { + "a.ts": "type D = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype Mk = K extends any ? { a: K } : never;\ntype S = Mk<`s${D}${D}${D}`>;\ntype T = Mk<`t${D}${D}${D}` | `u${D}${D}${D}` | `v${D}${D}`> | { a: string };\ndeclare let s: S; declare let t: T; declare const c: boolean;\nlet t2: T;\nt2 = t = s;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, + "87-R01k": { + "files": { + "a.ts": "interface I0 { n: I1 }\ninterface I1 { n: I2 }\ninterface I2 { n: I3 }\ninterface I3 { n: I4 }\ninterface I4 { n: I5 }\ninterface I5 { n: I6 }\ninterface I6 { n: I7 }\ninterface I7 { n: I8 }\ninterface I8 { n: I9 }\ninterface I9 { n: I10 }\ninterface I10 { n: I11 }\ninterface I11 { n: I12 }\ninterface I12 { n: I13 }\ninterface I13 { n: I14 }\ninterface I14 { n: I15 }\ninterface I15 { n: I16 }\ninterface I16 { n: I17 }\ninterface I17 { n: I18 }\ninterface I18 { n: I19 }\ninterface I19 { n: I20 }\ninterface I20 { n: I21 }\ninterface I21 { n: I22 }\ninterface I22 { n: I23 }\ninterface I23 { n: I24 }\ninterface I24 { n: I25 }\ninterface I25 { n: I26 }\ninterface I26 { n: I27 }\ninterface I27 { n: I28 }\ninterface I28 { n: I29 }\ninterface I29 { n: I30 }\ninterface I30 { n: I31 }\ninterface I31 { n: I32 }\ninterface I32 { n: I33 }\ninterface I33 { n: I34 }\ninterface I34 { n: I35 }\ninterface I35 { n: I36 }\ninterface I36 { n: I37 }\ninterface I37 { n: I38 }\ninterface I38 { n: I39 }\ninterface I39 { n: I40 }\ninterface I40 { n: I41 }\ninterface I41 { n: I42 }\ninterface I42 { n: I43 }\ninterface I43 { n: I44 }\ninterface I44 { n: I45 }\ninterface I45 { n: I46 }\ninterface I46 { n: I47 }\ninterface I47 { n: I48 }\ninterface I48 { n: I49 }\ninterface I49 { n: I50 }\ninterface I50 { n: I51 }\ninterface I51 { n: I52 }\ninterface I52 { n: I53 }\ninterface I53 { n: I54 }\ninterface I54 { n: I55 }\ninterface I55 { n: I56 }\ninterface I56 { n: I57 }\ninterface I57 { n: I58 }\ninterface I58 { n: I59 }\ninterface I59 { n: I60 }\ninterface I60 { n: I61 }\ninterface I61 { n: I62 }\ninterface I62 { n: I63 }\ninterface I63 { n: I64 }\ninterface I64 { n: I65 }\ninterface I65 { n: I66 }\ninterface I66 { n: I67 }\ninterface I67 { n: I68 }\ninterface I68 { n: I69 }\ninterface I69 { n: I70 }\ninterface I70 { n: I71 }\ninterface I71 { n: I72 }\ninterface I72 { n: I73 }\ninterface I73 { n: I74 }\ninterface I74 { n: I75 }\ninterface I75 { n: I76 }\ninterface I76 { n: I77 }\ninterface I77 { n: I78 }\ninterface I78 { n: I79 }\ninterface I79 { n: I80 }\ninterface I80 { n: I81 }\ninterface I81 { n: I82 }\ninterface I82 { n: I83 }\ninterface I83 { n: I84 }\ninterface I84 { n: I85 }\ninterface I85 { n: I86 }\ninterface I86 { n: I87 }\ninterface I87 { n: I88 }\ninterface I88 { n: I89 }\ninterface I89 { n: I90 }\ninterface I90 { n: I91 }\ninterface I91 { n: I92 }\ninterface I92 { n: I93 }\ninterface I93 { n: I94 }\ninterface I94 { n: I95 }\ninterface I95 { n: I96 }\ninterface I96 { n: I97 }\ninterface I97 { n: I98 }\ninterface I98 { n: I99 }\ninterface I99 { n: I100 }\ninterface I100 { n: I101 }\ninterface I101 { n: 1 }\ninterface J0 { n: J1 }\ninterface J1 { n: J2 }\ninterface J2 { n: J3 }\ninterface J3 { n: J4 }\ninterface J4 { n: J5 }\ninterface J5 { n: J6 }\ninterface J6 { n: J7 }\ninterface J7 { n: J8 }\ninterface J8 { n: J9 }\ninterface J9 { n: J10 }\ninterface J10 { n: J11 }\ninterface J11 { n: J12 }\ninterface J12 { n: J13 }\ninterface J13 { n: J14 }\ninterface J14 { n: J15 }\ninterface J15 { n: J16 }\ninterface J16 { n: J17 }\ninterface J17 { n: J18 }\ninterface J18 { n: J19 }\ninterface J19 { n: J20 }\ninterface J20 { n: J21 }\ninterface J21 { n: J22 }\ninterface J22 { n: J23 }\ninterface J23 { n: J24 }\ninterface J24 { n: J25 }\ninterface J25 { n: J26 }\ninterface J26 { n: J27 }\ninterface J27 { n: J28 }\ninterface J28 { n: J29 }\ninterface J29 { n: J30 }\ninterface J30 { n: J31 }\ninterface J31 { n: J32 }\ninterface J32 { n: J33 }\ninterface J33 { n: J34 }\ninterface J34 { n: J35 }\ninterface J35 { n: J36 }\ninterface J36 { n: J37 }\ninterface J37 { n: J38 }\ninterface J38 { n: J39 }\ninterface J39 { n: J40 }\ninterface J40 { n: J41 }\ninterface J41 { n: J42 }\ninterface J42 { n: J43 }\ninterface J43 { n: J44 }\ninterface J44 { n: J45 }\ninterface J45 { n: J46 }\ninterface J46 { n: J47 }\ninterface J47 { n: J48 }\ninterface J48 { n: J49 }\ninterface J49 { n: J50 }\ninterface J50 { n: J51 }\ninterface J51 { n: J52 }\ninterface J52 { n: J53 }\ninterface J53 { n: J54 }\ninterface J54 { n: J55 }\ninterface J55 { n: J56 }\ninterface J56 { n: J57 }\ninterface J57 { n: J58 }\ninterface J58 { n: J59 }\ninterface J59 { n: J60 }\ninterface J60 { n: J61 }\ninterface J61 { n: J62 }\ninterface J62 { n: J63 }\ninterface J63 { n: J64 }\ninterface J64 { n: J65 }\ninterface J65 { n: J66 }\ninterface J66 { n: J67 }\ninterface J67 { n: J68 }\ninterface J68 { n: J69 }\ninterface J69 { n: J70 }\ninterface J70 { n: J71 }\ninterface J71 { n: J72 }\ninterface J72 { n: J73 }\ninterface J73 { n: J74 }\ninterface J74 { n: J75 }\ninterface J75 { n: J76 }\ninterface J76 { n: J77 }\ninterface J77 { n: J78 }\ninterface J78 { n: J79 }\ninterface J79 { n: J80 }\ninterface J80 { n: J81 }\ninterface J81 { n: J82 }\ninterface J82 { n: J83 }\ninterface J83 { n: J84 }\ninterface J84 { n: J85 }\ninterface J85 { n: J86 }\ninterface J86 { n: J87 }\ninterface J87 { n: J88 }\ninterface J88 { n: J89 }\ninterface J89 { n: J90 }\ninterface J90 { n: J91 }\ninterface J91 { n: J92 }\ninterface J92 { n: J93 }\ninterface J93 { n: J94 }\ninterface J94 { n: J95 }\ninterface J95 { n: J96 }\ninterface J96 { n: J97 }\ninterface J97 { n: J98 }\ninterface J98 { n: J99 }\ninterface J99 { n: J100 }\ninterface J100 { n: J101 }\ninterface J101 { n: 1 }\ndeclare let i0: I0; declare let j0: J0; declare const c: boolean;\nvar v: I0;\nvar v: J0;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R03": { + "files": { + "a.ts": "function h1({ a = 1 }) {}\nfunction h2({ a = 1 }) {}\nfunction f1({}) {}\nfunction f2({}) {}\ntype H1 = Parameters[0]; type H2 = Parameters[0];\ntype F1 = Parameters[0]; type F2 = Parameters[0];\ndeclare let u1: H1 | H2; const e1: 0 = u1;\ndeclare let u2: F1 | F2; const e2: 0 = u2;\ndeclare let u3: H1 & H2; const e3: 0 = u3;\ndeclare let u4: F1 & F2; const e4: 0 = u4;\ndeclare const o: { a?: number; z: 1 }; const { z, ...r1 } = o; const { z: zz, ...r2 } = o;\ndeclare let u5: typeof r1 | typeof r2; const e5: 0 = u5;\ndeclare const p: { z: 1 }; const { z: z3, ...r3 } = p; const { z: z4, ...r4 } = p;\ndeclare let u6: typeof r3 | typeof r4; const e6: 0 = u6;\ndeclare let u7: typeof r3 & typeof r4; const e7: 0 = u7;\nconst s1 = { ...r3 }, s2 = { ...r4 };\ndeclare let u8: typeof s1 | typeof s2; const e8: 0 = u8;\nconst l1 = {}, l2 = {};\ndeclare let u9: typeof l1 | typeof l2; const e9: 0 = u9;\nfunction g({ a = 1 }, { a: b = 1 }) {}\ndeclare let u10: Parameters[number]; const e10: 0 = u10;\nconst [{ k = 1 }, { k: k2 = 1 }] = null! as any[];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R04a": { + "files": { + "a.ts": "function sp0(t: T) { return { ...{} }; }\nfunction rs0(t: T) { const { a, ...r } = { a: 1 }; return r; }\nfunction un(u: unknown) {\n const a: ReturnType> | null | undefined = u;\n const b: ReturnType> | null | undefined = u;\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R04b": { + "files": { + "a.ts": "function sp0(t: T) { return { ...{} }; }\nfunction rs0(t: T) { const { a, ...r } = { a: 1 }; return r; }\nconst c0 = sp0(1); declare let x0: string & typeof c0; const y0: 0 = x0;\nconst c3 = rs0(1); declare let x3: string & typeof c3; const y3: 0 = x3;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R05a": { + "files": { + "a.ts": "interface I0 { n: I1 }\ninterface I1 { n: I2 }\ninterface I2 { n: I3 }\ninterface I3 { n: I4 }\ninterface I4 { n: I5 }\ninterface I5 { n: I6 }\ninterface I6 { n: I7 }\ninterface I7 { n: I8 }\ninterface I8 { n: I9 }\ninterface I9 { n: I10 }\ninterface I10 { n: I11 }\ninterface I11 { n: I12 }\ninterface I12 { n: I13 }\ninterface I13 { n: I14 }\ninterface I14 { n: I15 }\ninterface I15 { n: I16 }\ninterface I16 { n: I17 }\ninterface I17 { n: I18 }\ninterface I18 { n: I19 }\ninterface I19 { n: I20 }\ninterface I20 { n: I21 }\ninterface I21 { n: I22 }\ninterface I22 { n: I23 }\ninterface I23 { n: I24 }\ninterface I24 { n: I25 }\ninterface I25 { n: I26 }\ninterface I26 { n: I27 }\ninterface I27 { n: I28 }\ninterface I28 { n: I29 }\ninterface I29 { n: I30 }\ninterface I30 { n: I31 }\ninterface I31 { n: I32 }\ninterface I32 { n: I33 }\ninterface I33 { n: I34 }\ninterface I34 { n: I35 }\ninterface I35 { n: I36 }\ninterface I36 { n: I37 }\ninterface I37 { n: I38 }\ninterface I38 { n: I39 }\ninterface I39 { n: I40 }\ninterface I40 { n: I41 }\ninterface I41 { n: I42 }\ninterface I42 { n: I43 }\ninterface I43 { n: I44 }\ninterface I44 { n: I45 }\ninterface I45 { n: I46 }\ninterface I46 { n: I47 }\ninterface I47 { n: I48 }\ninterface I48 { n: I49 }\ninterface I49 { n: I50 }\ninterface I50 { n: I51 }\ninterface I51 { n: I52 }\ninterface I52 { n: I53 }\ninterface I53 { n: I54 }\ninterface I54 { n: I55 }\ninterface I55 { n: I56 }\ninterface I56 { n: I57 }\ninterface I57 { n: I58 }\ninterface I58 { n: I59 }\ninterface I59 { n: I60 }\ninterface I60 { n: I61 }\ninterface I61 { n: I62 }\ninterface I62 { n: I63 }\ninterface I63 { n: I64 }\ninterface I64 { n: I65 }\ninterface I65 { n: I66 }\ninterface I66 { n: I67 }\ninterface I67 { n: I68 }\ninterface I68 { n: I69 }\ninterface I69 { n: I70 }\ninterface I70 { n: I71 }\ninterface I71 { n: I72 }\ninterface I72 { n: I73 }\ninterface I73 { n: I74 }\ninterface I74 { n: I75 }\ninterface I75 { n: I76 }\ninterface I76 { n: I77 }\ninterface I77 { n: I78 }\ninterface I78 { n: I79 }\ninterface I79 { n: I80 }\ninterface I80 { n: I81 }\ninterface I81 { n: I82 }\ninterface I82 { n: I83 }\ninterface I83 { n: I84 }\ninterface I84 { n: I85 }\ninterface I85 { n: I86 }\ninterface I86 { n: I87 }\ninterface I87 { n: I88 }\ninterface I88 { n: I89 }\ninterface I89 { n: I90 }\ninterface I90 { n: I91 }\ninterface I91 { n: I92 }\ninterface I92 { n: I93 }\ninterface I93 { n: I94 }\ninterface I94 { n: I95 }\ninterface I95 { n: I96 }\ninterface I96 { n: I97 }\ninterface I97 { n: I98 }\ninterface I98 { n: I99 }\ninterface I99 { n: I100 }\ninterface I100 { n: 1 }\ninterface J0 { n: J1 }\ninterface J1 { n: J2 }\ninterface J2 { n: J3 }\ninterface J3 { n: J4 }\ninterface J4 { n: J5 }\ninterface J5 { n: J6 }\ninterface J6 { n: J7 }\ninterface J7 { n: J8 }\ninterface J8 { n: J9 }\ninterface J9 { n: J10 }\ninterface J10 { n: J11 }\ninterface J11 { n: J12 }\ninterface J12 { n: J13 }\ninterface J13 { n: J14 }\ninterface J14 { n: J15 }\ninterface J15 { n: J16 }\ninterface J16 { n: J17 }\ninterface J17 { n: J18 }\ninterface J18 { n: J19 }\ninterface J19 { n: J20 }\ninterface J20 { n: J21 }\ninterface J21 { n: J22 }\ninterface J22 { n: J23 }\ninterface J23 { n: J24 }\ninterface J24 { n: J25 }\ninterface J25 { n: J26 }\ninterface J26 { n: J27 }\ninterface J27 { n: J28 }\ninterface J28 { n: J29 }\ninterface J29 { n: J30 }\ninterface J30 { n: J31 }\ninterface J31 { n: J32 }\ninterface J32 { n: J33 }\ninterface J33 { n: J34 }\ninterface J34 { n: J35 }\ninterface J35 { n: J36 }\ninterface J36 { n: J37 }\ninterface J37 { n: J38 }\ninterface J38 { n: J39 }\ninterface J39 { n: J40 }\ninterface J40 { n: J41 }\ninterface J41 { n: J42 }\ninterface J42 { n: J43 }\ninterface J43 { n: J44 }\ninterface J44 { n: J45 }\ninterface J45 { n: J46 }\ninterface J46 { n: J47 }\ninterface J47 { n: J48 }\ninterface J48 { n: J49 }\ninterface J49 { n: J50 }\ninterface J50 { n: J51 }\ninterface J51 { n: J52 }\ninterface J52 { n: J53 }\ninterface J53 { n: J54 }\ninterface J54 { n: J55 }\ninterface J55 { n: J56 }\ninterface J56 { n: J57 }\ninterface J57 { n: J58 }\ninterface J58 { n: J59 }\ninterface J59 { n: J60 }\ninterface J60 { n: J61 }\ninterface J61 { n: J62 }\ninterface J62 { n: J63 }\ninterface J63 { n: J64 }\ninterface J64 { n: J65 }\ninterface J65 { n: J66 }\ninterface J66 { n: J67 }\ninterface J67 { n: J68 }\ninterface J68 { n: J69 }\ninterface J69 { n: J70 }\ninterface J70 { n: J71 }\ninterface J71 { n: J72 }\ninterface J72 { n: J73 }\ninterface J73 { n: J74 }\ninterface J74 { n: J75 }\ninterface J75 { n: J76 }\ninterface J76 { n: J77 }\ninterface J77 { n: J78 }\ninterface J78 { n: J79 }\ninterface J79 { n: J80 }\ninterface J80 { n: J81 }\ninterface J81 { n: J82 }\ninterface J82 { n: J83 }\ninterface J83 { n: J84 }\ninterface J84 { n: J85 }\ninterface J85 { n: J86 }\ninterface J86 { n: J87 }\ninterface J87 { n: J88 }\ninterface J88 { n: J89 }\ninterface J89 { n: J90 }\ninterface J90 { n: J91 }\ninterface J91 { n: J92 }\ninterface J92 { n: J93 }\ninterface J93 { n: J94 }\ninterface J94 { n: J95 }\ninterface J95 { n: J96 }\ninterface J96 { n: J97 }\ninterface J97 { n: J98 }\ninterface J98 { n: J99 }\ninterface J99 { n: J100 }\ninterface J100 { n: 1 }\ndeclare let i0: I0; declare let jj: J0; declare const c: boolean;\njj = i0;\ntype T = I99 extends J99 ? 1 : 2;\nconst k: T = 0;\ntype T50 = I50 extends J50 ? 1 : 2;\nconst k50: T50 = 0;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R05b": { + "files": { + "a.ts": "interface I0 { n: I1 }\ninterface I1 { n: I2 }\ninterface I2 { n: I3 }\ninterface I3 { n: I4 }\ninterface I4 { n: I5 }\ninterface I5 { n: I6 }\ninterface I6 { n: I7 }\ninterface I7 { n: I8 }\ninterface I8 { n: I9 }\ninterface I9 { n: I10 }\ninterface I10 { n: I11 }\ninterface I11 { n: I12 }\ninterface I12 { n: I13 }\ninterface I13 { n: I14 }\ninterface I14 { n: I15 }\ninterface I15 { n: I16 }\ninterface I16 { n: I17 }\ninterface I17 { n: I18 }\ninterface I18 { n: I19 }\ninterface I19 { n: I20 }\ninterface I20 { n: I21 }\ninterface I21 { n: I22 }\ninterface I22 { n: I23 }\ninterface I23 { n: I24 }\ninterface I24 { n: I25 }\ninterface I25 { n: I26 }\ninterface I26 { n: I27 }\ninterface I27 { n: I28 }\ninterface I28 { n: I29 }\ninterface I29 { n: I30 }\ninterface I30 { n: I31 }\ninterface I31 { n: I32 }\ninterface I32 { n: I33 }\ninterface I33 { n: I34 }\ninterface I34 { n: I35 }\ninterface I35 { n: I36 }\ninterface I36 { n: I37 }\ninterface I37 { n: I38 }\ninterface I38 { n: I39 }\ninterface I39 { n: I40 }\ninterface I40 { n: I41 }\ninterface I41 { n: I42 }\ninterface I42 { n: I43 }\ninterface I43 { n: I44 }\ninterface I44 { n: I45 }\ninterface I45 { n: I46 }\ninterface I46 { n: I47 }\ninterface I47 { n: I48 }\ninterface I48 { n: I49 }\ninterface I49 { n: I50 }\ninterface I50 { n: I51 }\ninterface I51 { n: I52 }\ninterface I52 { n: I53 }\ninterface I53 { n: I54 }\ninterface I54 { n: I55 }\ninterface I55 { n: I56 }\ninterface I56 { n: I57 }\ninterface I57 { n: I58 }\ninterface I58 { n: I59 }\ninterface I59 { n: I60 }\ninterface I60 { n: I61 }\ninterface I61 { n: I62 }\ninterface I62 { n: I63 }\ninterface I63 { n: I64 }\ninterface I64 { n: I65 }\ninterface I65 { n: I66 }\ninterface I66 { n: I67 }\ninterface I67 { n: I68 }\ninterface I68 { n: I69 }\ninterface I69 { n: I70 }\ninterface I70 { n: I71 }\ninterface I71 { n: I72 }\ninterface I72 { n: I73 }\ninterface I73 { n: I74 }\ninterface I74 { n: I75 }\ninterface I75 { n: I76 }\ninterface I76 { n: I77 }\ninterface I77 { n: I78 }\ninterface I78 { n: I79 }\ninterface I79 { n: I80 }\ninterface I80 { n: I81 }\ninterface I81 { n: I82 }\ninterface I82 { n: I83 }\ninterface I83 { n: I84 }\ninterface I84 { n: I85 }\ninterface I85 { n: I86 }\ninterface I86 { n: I87 }\ninterface I87 { n: I88 }\ninterface I88 { n: I89 }\ninterface I89 { n: I90 }\ninterface I90 { n: I91 }\ninterface I91 { n: I92 }\ninterface I92 { n: I93 }\ninterface I93 { n: I94 }\ninterface I94 { n: I95 }\ninterface I95 { n: I96 }\ninterface I96 { n: I97 }\ninterface I97 { n: I98 }\ninterface I98 { n: I99 }\ninterface I99 { n: I100 }\ninterface I100 { n: 1 }\ninterface J0 { n: J1 }\ninterface J1 { n: J2 }\ninterface J2 { n: J3 }\ninterface J3 { n: J4 }\ninterface J4 { n: J5 }\ninterface J5 { n: J6 }\ninterface J6 { n: J7 }\ninterface J7 { n: J8 }\ninterface J8 { n: J9 }\ninterface J9 { n: J10 }\ninterface J10 { n: J11 }\ninterface J11 { n: J12 }\ninterface J12 { n: J13 }\ninterface J13 { n: J14 }\ninterface J14 { n: J15 }\ninterface J15 { n: J16 }\ninterface J16 { n: J17 }\ninterface J17 { n: J18 }\ninterface J18 { n: J19 }\ninterface J19 { n: J20 }\ninterface J20 { n: J21 }\ninterface J21 { n: J22 }\ninterface J22 { n: J23 }\ninterface J23 { n: J24 }\ninterface J24 { n: J25 }\ninterface J25 { n: J26 }\ninterface J26 { n: J27 }\ninterface J27 { n: J28 }\ninterface J28 { n: J29 }\ninterface J29 { n: J30 }\ninterface J30 { n: J31 }\ninterface J31 { n: J32 }\ninterface J32 { n: J33 }\ninterface J33 { n: J34 }\ninterface J34 { n: J35 }\ninterface J35 { n: J36 }\ninterface J36 { n: J37 }\ninterface J37 { n: J38 }\ninterface J38 { n: J39 }\ninterface J39 { n: J40 }\ninterface J40 { n: J41 }\ninterface J41 { n: J42 }\ninterface J42 { n: J43 }\ninterface J43 { n: J44 }\ninterface J44 { n: J45 }\ninterface J45 { n: J46 }\ninterface J46 { n: J47 }\ninterface J47 { n: J48 }\ninterface J48 { n: J49 }\ninterface J49 { n: J50 }\ninterface J50 { n: J51 }\ninterface J51 { n: J52 }\ninterface J52 { n: J53 }\ninterface J53 { n: J54 }\ninterface J54 { n: J55 }\ninterface J55 { n: J56 }\ninterface J56 { n: J57 }\ninterface J57 { n: J58 }\ninterface J58 { n: J59 }\ninterface J59 { n: J60 }\ninterface J60 { n: J61 }\ninterface J61 { n: J62 }\ninterface J62 { n: J63 }\ninterface J63 { n: J64 }\ninterface J64 { n: J65 }\ninterface J65 { n: J66 }\ninterface J66 { n: J67 }\ninterface J67 { n: J68 }\ninterface J68 { n: J69 }\ninterface J69 { n: J70 }\ninterface J70 { n: J71 }\ninterface J71 { n: J72 }\ninterface J72 { n: J73 }\ninterface J73 { n: J74 }\ninterface J74 { n: J75 }\ninterface J75 { n: J76 }\ninterface J76 { n: J77 }\ninterface J77 { n: J78 }\ninterface J78 { n: J79 }\ninterface J79 { n: J80 }\ninterface J80 { n: J81 }\ninterface J81 { n: J82 }\ninterface J82 { n: J83 }\ninterface J83 { n: J84 }\ninterface J84 { n: J85 }\ninterface J85 { n: J86 }\ninterface J86 { n: J87 }\ninterface J87 { n: J88 }\ninterface J88 { n: J89 }\ninterface J89 { n: J90 }\ninterface J90 { n: J91 }\ninterface J91 { n: J92 }\ninterface J92 { n: J93 }\ninterface J93 { n: J94 }\ninterface J94 { n: J95 }\ninterface J95 { n: J96 }\ninterface J96 { n: J97 }\ninterface J97 { n: J98 }\ninterface J98 { n: J99 }\ninterface J99 { n: J100 }\ninterface J100 { n: 1 }\ndeclare let i0: I0; declare let jj: J0; declare const c: boolean;\nconst o: { p: J0 } = { p: i0 };\ntype T = I99 extends J99 ? 1 : 2;\nconst k: T = 0;\ntype T50 = I50 extends J50 ? 1 : 2;\nconst k50: T50 = 0;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R05c": { + "files": { + "a.ts": "interface I0 { n: I1 }\ninterface I1 { n: I2 }\ninterface I2 { n: I3 }\ninterface I3 { n: I4 }\ninterface I4 { n: I5 }\ninterface I5 { n: I6 }\ninterface I6 { n: I7 }\ninterface I7 { n: I8 }\ninterface I8 { n: I9 }\ninterface I9 { n: I10 }\ninterface I10 { n: I11 }\ninterface I11 { n: I12 }\ninterface I12 { n: I13 }\ninterface I13 { n: I14 }\ninterface I14 { n: I15 }\ninterface I15 { n: I16 }\ninterface I16 { n: I17 }\ninterface I17 { n: I18 }\ninterface I18 { n: I19 }\ninterface I19 { n: I20 }\ninterface I20 { n: I21 }\ninterface I21 { n: I22 }\ninterface I22 { n: I23 }\ninterface I23 { n: I24 }\ninterface I24 { n: I25 }\ninterface I25 { n: I26 }\ninterface I26 { n: I27 }\ninterface I27 { n: I28 }\ninterface I28 { n: I29 }\ninterface I29 { n: I30 }\ninterface I30 { n: I31 }\ninterface I31 { n: I32 }\ninterface I32 { n: I33 }\ninterface I33 { n: I34 }\ninterface I34 { n: I35 }\ninterface I35 { n: I36 }\ninterface I36 { n: I37 }\ninterface I37 { n: I38 }\ninterface I38 { n: I39 }\ninterface I39 { n: I40 }\ninterface I40 { n: I41 }\ninterface I41 { n: I42 }\ninterface I42 { n: I43 }\ninterface I43 { n: I44 }\ninterface I44 { n: I45 }\ninterface I45 { n: I46 }\ninterface I46 { n: I47 }\ninterface I47 { n: I48 }\ninterface I48 { n: I49 }\ninterface I49 { n: I50 }\ninterface I50 { n: I51 }\ninterface I51 { n: I52 }\ninterface I52 { n: I53 }\ninterface I53 { n: I54 }\ninterface I54 { n: I55 }\ninterface I55 { n: I56 }\ninterface I56 { n: I57 }\ninterface I57 { n: I58 }\ninterface I58 { n: I59 }\ninterface I59 { n: I60 }\ninterface I60 { n: I61 }\ninterface I61 { n: I62 }\ninterface I62 { n: I63 }\ninterface I63 { n: I64 }\ninterface I64 { n: I65 }\ninterface I65 { n: I66 }\ninterface I66 { n: I67 }\ninterface I67 { n: I68 }\ninterface I68 { n: I69 }\ninterface I69 { n: I70 }\ninterface I70 { n: I71 }\ninterface I71 { n: I72 }\ninterface I72 { n: I73 }\ninterface I73 { n: I74 }\ninterface I74 { n: I75 }\ninterface I75 { n: I76 }\ninterface I76 { n: I77 }\ninterface I77 { n: I78 }\ninterface I78 { n: I79 }\ninterface I79 { n: I80 }\ninterface I80 { n: I81 }\ninterface I81 { n: I82 }\ninterface I82 { n: I83 }\ninterface I83 { n: I84 }\ninterface I84 { n: I85 }\ninterface I85 { n: I86 }\ninterface I86 { n: I87 }\ninterface I87 { n: I88 }\ninterface I88 { n: I89 }\ninterface I89 { n: I90 }\ninterface I90 { n: I91 }\ninterface I91 { n: I92 }\ninterface I92 { n: I93 }\ninterface I93 { n: I94 }\ninterface I94 { n: I95 }\ninterface I95 { n: I96 }\ninterface I96 { n: I97 }\ninterface I97 { n: I98 }\ninterface I98 { n: I99 }\ninterface I99 { n: I100 }\ninterface I100 { n: 1 }\ninterface J0 { n: J1 }\ninterface J1 { n: J2 }\ninterface J2 { n: J3 }\ninterface J3 { n: J4 }\ninterface J4 { n: J5 }\ninterface J5 { n: J6 }\ninterface J6 { n: J7 }\ninterface J7 { n: J8 }\ninterface J8 { n: J9 }\ninterface J9 { n: J10 }\ninterface J10 { n: J11 }\ninterface J11 { n: J12 }\ninterface J12 { n: J13 }\ninterface J13 { n: J14 }\ninterface J14 { n: J15 }\ninterface J15 { n: J16 }\ninterface J16 { n: J17 }\ninterface J17 { n: J18 }\ninterface J18 { n: J19 }\ninterface J19 { n: J20 }\ninterface J20 { n: J21 }\ninterface J21 { n: J22 }\ninterface J22 { n: J23 }\ninterface J23 { n: J24 }\ninterface J24 { n: J25 }\ninterface J25 { n: J26 }\ninterface J26 { n: J27 }\ninterface J27 { n: J28 }\ninterface J28 { n: J29 }\ninterface J29 { n: J30 }\ninterface J30 { n: J31 }\ninterface J31 { n: J32 }\ninterface J32 { n: J33 }\ninterface J33 { n: J34 }\ninterface J34 { n: J35 }\ninterface J35 { n: J36 }\ninterface J36 { n: J37 }\ninterface J37 { n: J38 }\ninterface J38 { n: J39 }\ninterface J39 { n: J40 }\ninterface J40 { n: J41 }\ninterface J41 { n: J42 }\ninterface J42 { n: J43 }\ninterface J43 { n: J44 }\ninterface J44 { n: J45 }\ninterface J45 { n: J46 }\ninterface J46 { n: J47 }\ninterface J47 { n: J48 }\ninterface J48 { n: J49 }\ninterface J49 { n: J50 }\ninterface J50 { n: J51 }\ninterface J51 { n: J52 }\ninterface J52 { n: J53 }\ninterface J53 { n: J54 }\ninterface J54 { n: J55 }\ninterface J55 { n: J56 }\ninterface J56 { n: J57 }\ninterface J57 { n: J58 }\ninterface J58 { n: J59 }\ninterface J59 { n: J60 }\ninterface J60 { n: J61 }\ninterface J61 { n: J62 }\ninterface J62 { n: J63 }\ninterface J63 { n: J64 }\ninterface J64 { n: J65 }\ninterface J65 { n: J66 }\ninterface J66 { n: J67 }\ninterface J67 { n: J68 }\ninterface J68 { n: J69 }\ninterface J69 { n: J70 }\ninterface J70 { n: J71 }\ninterface J71 { n: J72 }\ninterface J72 { n: J73 }\ninterface J73 { n: J74 }\ninterface J74 { n: J75 }\ninterface J75 { n: J76 }\ninterface J76 { n: J77 }\ninterface J77 { n: J78 }\ninterface J78 { n: J79 }\ninterface J79 { n: J80 }\ninterface J80 { n: J81 }\ninterface J81 { n: J82 }\ninterface J82 { n: J83 }\ninterface J83 { n: J84 }\ninterface J84 { n: J85 }\ninterface J85 { n: J86 }\ninterface J86 { n: J87 }\ninterface J87 { n: J88 }\ninterface J88 { n: J89 }\ninterface J89 { n: J90 }\ninterface J90 { n: J91 }\ninterface J91 { n: J92 }\ninterface J92 { n: J93 }\ninterface J93 { n: J94 }\ninterface J94 { n: J95 }\ninterface J95 { n: J96 }\ninterface J96 { n: J97 }\ninterface J97 { n: J98 }\ninterface J98 { n: J99 }\ninterface J99 { n: J100 }\ninterface J100 { n: 1 }\ndeclare let i0: I0; declare let jj: J0; declare const c: boolean;\ninterface A { p: J0 }\nclass B implements A { p!: I0 }\ntype T = I99 extends J99 ? 1 : 2;\nconst k: T = 0;\ntype T50 = I50 extends J50 ? 1 : 2;\nconst k50: T50 = 0;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R05d": { + "files": { + "a.ts": "interface I0 { n: I1 }\ninterface I1 { n: I2 }\ninterface I2 { n: I3 }\ninterface I3 { n: I4 }\ninterface I4 { n: I5 }\ninterface I5 { n: I6 }\ninterface I6 { n: I7 }\ninterface I7 { n: I8 }\ninterface I8 { n: I9 }\ninterface I9 { n: I10 }\ninterface I10 { n: I11 }\ninterface I11 { n: I12 }\ninterface I12 { n: I13 }\ninterface I13 { n: I14 }\ninterface I14 { n: I15 }\ninterface I15 { n: I16 }\ninterface I16 { n: I17 }\ninterface I17 { n: I18 }\ninterface I18 { n: I19 }\ninterface I19 { n: I20 }\ninterface I20 { n: I21 }\ninterface I21 { n: I22 }\ninterface I22 { n: I23 }\ninterface I23 { n: I24 }\ninterface I24 { n: I25 }\ninterface I25 { n: I26 }\ninterface I26 { n: I27 }\ninterface I27 { n: I28 }\ninterface I28 { n: I29 }\ninterface I29 { n: I30 }\ninterface I30 { n: I31 }\ninterface I31 { n: I32 }\ninterface I32 { n: I33 }\ninterface I33 { n: I34 }\ninterface I34 { n: I35 }\ninterface I35 { n: I36 }\ninterface I36 { n: I37 }\ninterface I37 { n: I38 }\ninterface I38 { n: I39 }\ninterface I39 { n: I40 }\ninterface I40 { n: I41 }\ninterface I41 { n: I42 }\ninterface I42 { n: I43 }\ninterface I43 { n: I44 }\ninterface I44 { n: I45 }\ninterface I45 { n: I46 }\ninterface I46 { n: I47 }\ninterface I47 { n: I48 }\ninterface I48 { n: I49 }\ninterface I49 { n: I50 }\ninterface I50 { n: I51 }\ninterface I51 { n: I52 }\ninterface I52 { n: I53 }\ninterface I53 { n: I54 }\ninterface I54 { n: I55 }\ninterface I55 { n: I56 }\ninterface I56 { n: I57 }\ninterface I57 { n: I58 }\ninterface I58 { n: I59 }\ninterface I59 { n: I60 }\ninterface I60 { n: I61 }\ninterface I61 { n: I62 }\ninterface I62 { n: I63 }\ninterface I63 { n: I64 }\ninterface I64 { n: I65 }\ninterface I65 { n: I66 }\ninterface I66 { n: I67 }\ninterface I67 { n: I68 }\ninterface I68 { n: I69 }\ninterface I69 { n: I70 }\ninterface I70 { n: I71 }\ninterface I71 { n: I72 }\ninterface I72 { n: I73 }\ninterface I73 { n: I74 }\ninterface I74 { n: I75 }\ninterface I75 { n: I76 }\ninterface I76 { n: I77 }\ninterface I77 { n: I78 }\ninterface I78 { n: I79 }\ninterface I79 { n: I80 }\ninterface I80 { n: I81 }\ninterface I81 { n: I82 }\ninterface I82 { n: I83 }\ninterface I83 { n: I84 }\ninterface I84 { n: I85 }\ninterface I85 { n: I86 }\ninterface I86 { n: I87 }\ninterface I87 { n: I88 }\ninterface I88 { n: I89 }\ninterface I89 { n: I90 }\ninterface I90 { n: I91 }\ninterface I91 { n: I92 }\ninterface I92 { n: I93 }\ninterface I93 { n: I94 }\ninterface I94 { n: I95 }\ninterface I95 { n: I96 }\ninterface I96 { n: I97 }\ninterface I97 { n: I98 }\ninterface I98 { n: I99 }\ninterface I99 { n: I100 }\ninterface I100 { n: 1 }\ninterface J0 { n: J1 }\ninterface J1 { n: J2 }\ninterface J2 { n: J3 }\ninterface J3 { n: J4 }\ninterface J4 { n: J5 }\ninterface J5 { n: J6 }\ninterface J6 { n: J7 }\ninterface J7 { n: J8 }\ninterface J8 { n: J9 }\ninterface J9 { n: J10 }\ninterface J10 { n: J11 }\ninterface J11 { n: J12 }\ninterface J12 { n: J13 }\ninterface J13 { n: J14 }\ninterface J14 { n: J15 }\ninterface J15 { n: J16 }\ninterface J16 { n: J17 }\ninterface J17 { n: J18 }\ninterface J18 { n: J19 }\ninterface J19 { n: J20 }\ninterface J20 { n: J21 }\ninterface J21 { n: J22 }\ninterface J22 { n: J23 }\ninterface J23 { n: J24 }\ninterface J24 { n: J25 }\ninterface J25 { n: J26 }\ninterface J26 { n: J27 }\ninterface J27 { n: J28 }\ninterface J28 { n: J29 }\ninterface J29 { n: J30 }\ninterface J30 { n: J31 }\ninterface J31 { n: J32 }\ninterface J32 { n: J33 }\ninterface J33 { n: J34 }\ninterface J34 { n: J35 }\ninterface J35 { n: J36 }\ninterface J36 { n: J37 }\ninterface J37 { n: J38 }\ninterface J38 { n: J39 }\ninterface J39 { n: J40 }\ninterface J40 { n: J41 }\ninterface J41 { n: J42 }\ninterface J42 { n: J43 }\ninterface J43 { n: J44 }\ninterface J44 { n: J45 }\ninterface J45 { n: J46 }\ninterface J46 { n: J47 }\ninterface J47 { n: J48 }\ninterface J48 { n: J49 }\ninterface J49 { n: J50 }\ninterface J50 { n: J51 }\ninterface J51 { n: J52 }\ninterface J52 { n: J53 }\ninterface J53 { n: J54 }\ninterface J54 { n: J55 }\ninterface J55 { n: J56 }\ninterface J56 { n: J57 }\ninterface J57 { n: J58 }\ninterface J58 { n: J59 }\ninterface J59 { n: J60 }\ninterface J60 { n: J61 }\ninterface J61 { n: J62 }\ninterface J62 { n: J63 }\ninterface J63 { n: J64 }\ninterface J64 { n: J65 }\ninterface J65 { n: J66 }\ninterface J66 { n: J67 }\ninterface J67 { n: J68 }\ninterface J68 { n: J69 }\ninterface J69 { n: J70 }\ninterface J70 { n: J71 }\ninterface J71 { n: J72 }\ninterface J72 { n: J73 }\ninterface J73 { n: J74 }\ninterface J74 { n: J75 }\ninterface J75 { n: J76 }\ninterface J76 { n: J77 }\ninterface J77 { n: J78 }\ninterface J78 { n: J79 }\ninterface J79 { n: J80 }\ninterface J80 { n: J81 }\ninterface J81 { n: J82 }\ninterface J82 { n: J83 }\ninterface J83 { n: J84 }\ninterface J84 { n: J85 }\ninterface J85 { n: J86 }\ninterface J86 { n: J87 }\ninterface J87 { n: J88 }\ninterface J88 { n: J89 }\ninterface J89 { n: J90 }\ninterface J90 { n: J91 }\ninterface J91 { n: J92 }\ninterface J92 { n: J93 }\ninterface J93 { n: J94 }\ninterface J94 { n: J95 }\ninterface J95 { n: J96 }\ninterface J96 { n: J97 }\ninterface J97 { n: J98 }\ninterface J98 { n: J99 }\ninterface J99 { n: J100 }\ninterface J100 { n: 1 }\ndeclare let i0: I0; declare let jj: J0; declare const c: boolean;\nfunction h(): I0;\nfunction h(): J0 { return jj; }\ntype T = I99 extends J99 ? 1 : 2;\nconst k: T = 0;\ntype T50 = I50 extends J50 ? 1 : 2;\nconst k50: T50 = 0;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R08": { + "files": { + "a.ts": "declare const o1: { a: 1 };\nlet a1: number;\n({ 1n: a1 } = o1);\n({ 1n: a1 = 2 } = o1);\n[{ 0x1n: a1 }] = [o1];\nfor ({ 1n: a1 } of [o1]) {}\n({ 1n: missing } = o1);\n({ 1n: a1, ...o1 } = o1);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"esnext\" } }\n" + } + }, + "87-R17b": { + "files": { + "a.ts": "import \"pkg\";\ndeclare module \"pkg\" { enum E { B } enum F { B = 2 } const enum G { B = 2 } }\nconst sentinel: number = \"\";\n", + "node_modules/pkg/index.d.ts": "export declare enum E { A }\nexport declare const enum F { A = 1 }\nexport declare enum G { A = 1 }\n", + "node_modules/pkg/package.json": "{ \"name\": \"pkg\", \"version\": \"1.0.0\", \"types\": \"index.d.ts\" }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"skipLibCheck\": true, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "87-R17c": { + "files": { + "a.ts": "var globalThis: number;\nvar x1 = 1;\nconst r1: 0 = globalThis;\nconst r2: 0 = globalThis.x1;\nconst r3: typeof globalThis = 1;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R18a": { + "files": { + "a.ts": "interface I0 { n: I1 }\ninterface I1 { n: I2 }\ninterface I2 { n: I3 }\ninterface I3 { n: I4 }\ninterface I4 { n: I5 }\ninterface I5 { n: I6 }\ninterface I6 { n: I7 }\ninterface I7 { n: I8 }\ninterface I8 { n: I9 }\ninterface I9 { n: I10 }\ninterface I10 { n: I11 }\ninterface I11 { n: I12 }\ninterface I12 { n: I13 }\ninterface I13 { n: I14 }\ninterface I14 { n: I15 }\ninterface I15 { n: I16 }\ninterface I16 { n: I17 }\ninterface I17 { n: I18 }\ninterface I18 { n: I19 }\ninterface I19 { n: I20 }\ninterface I20 { n: I21 }\ninterface I21 { n: I22 }\ninterface I22 { n: I23 }\ninterface I23 { n: I24 }\ninterface I24 { n: I25 }\ninterface I25 { n: I26 }\ninterface I26 { n: I27 }\ninterface I27 { n: I28 }\ninterface I28 { n: I29 }\ninterface I29 { n: I30 }\ninterface I30 { n: I31 }\ninterface I31 { n: I32 }\ninterface I32 { n: I33 }\ninterface I33 { n: I34 }\ninterface I34 { n: I35 }\ninterface I35 { n: I36 }\ninterface I36 { n: I37 }\ninterface I37 { n: I38 }\ninterface I38 { n: I39 }\ninterface I39 { n: I40 }\ninterface I40 { n: I41 }\ninterface I41 { n: I42 }\ninterface I42 { n: I43 }\ninterface I43 { n: I44 }\ninterface I44 { n: I45 }\ninterface I45 { n: I46 }\ninterface I46 { n: I47 }\ninterface I47 { n: I48 }\ninterface I48 { n: I49 }\ninterface I49 { n: I50 }\ninterface I50 { n: I51 }\ninterface I51 { n: I52 }\ninterface I52 { n: I53 }\ninterface I53 { n: I54 }\ninterface I54 { n: I55 }\ninterface I55 { n: I56 }\ninterface I56 { n: I57 }\ninterface I57 { n: I58 }\ninterface I58 { n: I59 }\ninterface I59 { n: I60 }\ninterface I60 { n: I61 }\ninterface I61 { n: I62 }\ninterface I62 { n: I63 }\ninterface I63 { n: I64 }\ninterface I64 { n: I65 }\ninterface I65 { n: I66 }\ninterface I66 { n: I67 }\ninterface I67 { n: I68 }\ninterface I68 { n: I69 }\ninterface I69 { n: I70 }\ninterface I70 { n: I71 }\ninterface I71 { n: I72 }\ninterface I72 { n: I73 }\ninterface I73 { n: I74 }\ninterface I74 { n: I75 }\ninterface I75 { n: I76 }\ninterface I76 { n: I77 }\ninterface I77 { n: I78 }\ninterface I78 { n: I79 }\ninterface I79 { n: I80 }\ninterface I80 { n: I81 }\ninterface I81 { n: I82 }\ninterface I82 { n: I83 }\ninterface I83 { n: I84 }\ninterface I84 { n: I85 }\ninterface I85 { n: I86 }\ninterface I86 { n: I87 }\ninterface I87 { n: I88 }\ninterface I88 { n: I89 }\ninterface I89 { n: I90 }\ninterface I90 { n: I91 }\ninterface I91 { n: I92 }\ninterface I92 { n: I93 }\ninterface I93 { n: I94 }\ninterface I94 { n: I95 }\ninterface I95 { n: I96 }\ninterface I96 { n: I97 }\ninterface I97 { n: I98 }\ninterface I98 { n: I99 }\ninterface I99 { n: I100 }\ninterface I100 { n: 1 }\ninterface J0 { n: J1 }\ninterface J1 { n: J2 }\ninterface J2 { n: J3 }\ninterface J3 { n: J4 }\ninterface J4 { n: J5 }\ninterface J5 { n: J6 }\ninterface J6 { n: J7 }\ninterface J7 { n: J8 }\ninterface J8 { n: J9 }\ninterface J9 { n: J10 }\ninterface J10 { n: J11 }\ninterface J11 { n: J12 }\ninterface J12 { n: J13 }\ninterface J13 { n: J14 }\ninterface J14 { n: J15 }\ninterface J15 { n: J16 }\ninterface J16 { n: J17 }\ninterface J17 { n: J18 }\ninterface J18 { n: J19 }\ninterface J19 { n: J20 }\ninterface J20 { n: J21 }\ninterface J21 { n: J22 }\ninterface J22 { n: J23 }\ninterface J23 { n: J24 }\ninterface J24 { n: J25 }\ninterface J25 { n: J26 }\ninterface J26 { n: J27 }\ninterface J27 { n: J28 }\ninterface J28 { n: J29 }\ninterface J29 { n: J30 }\ninterface J30 { n: J31 }\ninterface J31 { n: J32 }\ninterface J32 { n: J33 }\ninterface J33 { n: J34 }\ninterface J34 { n: J35 }\ninterface J35 { n: J36 }\ninterface J36 { n: J37 }\ninterface J37 { n: J38 }\ninterface J38 { n: J39 }\ninterface J39 { n: J40 }\ninterface J40 { n: J41 }\ninterface J41 { n: J42 }\ninterface J42 { n: J43 }\ninterface J43 { n: J44 }\ninterface J44 { n: J45 }\ninterface J45 { n: J46 }\ninterface J46 { n: J47 }\ninterface J47 { n: J48 }\ninterface J48 { n: J49 }\ninterface J49 { n: J50 }\ninterface J50 { n: J51 }\ninterface J51 { n: J52 }\ninterface J52 { n: J53 }\ninterface J53 { n: J54 }\ninterface J54 { n: J55 }\ninterface J55 { n: J56 }\ninterface J56 { n: J57 }\ninterface J57 { n: J58 }\ninterface J58 { n: J59 }\ninterface J59 { n: J60 }\ninterface J60 { n: J61 }\ninterface J61 { n: J62 }\ninterface J62 { n: J63 }\ninterface J63 { n: J64 }\ninterface J64 { n: J65 }\ninterface J65 { n: J66 }\ninterface J66 { n: J67 }\ninterface J67 { n: J68 }\ninterface J68 { n: J69 }\ninterface J69 { n: J70 }\ninterface J70 { n: J71 }\ninterface J71 { n: J72 }\ninterface J72 { n: J73 }\ninterface J73 { n: J74 }\ninterface J74 { n: J75 }\ninterface J75 { n: J76 }\ninterface J76 { n: J77 }\ninterface J77 { n: J78 }\ninterface J78 { n: J79 }\ninterface J79 { n: J80 }\ninterface J80 { n: J81 }\ninterface J81 { n: J82 }\ninterface J82 { n: J83 }\ninterface J83 { n: J84 }\ninterface J84 { n: J85 }\ninterface J85 { n: J86 }\ninterface J86 { n: J87 }\ninterface J87 { n: J88 }\ninterface J88 { n: J89 }\ninterface J89 { n: J90 }\ninterface J90 { n: J91 }\ninterface J91 { n: J92 }\ninterface J92 { n: J93 }\ninterface J93 { n: J94 }\ninterface J94 { n: J95 }\ninterface J95 { n: J96 }\ninterface J96 { n: J97 }\ninterface J97 { n: J98 }\ninterface J98 { n: J99 }\ninterface J99 { n: J100 }\ninterface J100 { n: 1 }\ndeclare let i0: I0; declare let j0: J0; declare let i99: I99; declare let j99: J99; declare let i50: I50; declare let j50: J50; declare const c: boolean;\nvar use = f2();\nconst fn = () => { if (i99 === j99) {} };\nfunction f2() { return i0 as J0; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "87-R18b": { + "files": { + "a.ts": "var use = f2();\nconst fn = () => { const v: 1 = null! as Has<\"$m\", D8>; };\nfunction f2() { return null! as D8; }\nconst sentinel: number = \"\";\n", + "d.d.ts": "type Has = K extends keyof T ? true : false;\ntype renamed = { [K in keyof T as `$${K & string}`]: T[K] };\ninterface D8 extends renamed { m(): void; n: number }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"skipLibCheck\": true } }\n" + } + }, + "87-R20a": { + "files": { + "a.ts": "export async function f() {}\n", + "b.ts": "import { f } from \"./a\";\nf();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{\"compilerOptions\":{\"target\":\"es2018\",\"lib\":[\"es5\"],\"noEmit\":true,\"module\":\"commonjs\"},\"files\":[\"a.ts\",\"b.ts\"]}\n" + } + }, + "88-R02a": { + "files": { + "index.ts": "/// \nconst a: ABC = { abc: 1 };\nconst b: string = libValue;\nconst c: number = libBad;\nconst d: string = libFn(1, 2);\nconst e: string = new LibClass().m();\nconst f: string = new LibClass().p;\nwindow.localStorage;\nconst sentinel: number = \"\";\n", + "node_modules/@typescript/lib-dom/index.ts": "interface ABC { abc: string }\nvar libValue = 1;\nvar libBad: string = 2;\nfunction libFn(a, b) { return a + b + missingName; }\nclass LibClass { p = 1; m() { return this.p.nope; } }\nasync function libAsync() {}\nfunction libRec1() { return [libRec2()]; }\nfunction libRec2() { return [libRec1()]; }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"target\": \"es2015\", \"libReplacement\": true, \"noEmit\": true, \"strict\": true, \"types\": [], \"skipLibCheck\": true }, \"files\": [\"index.ts\"] }\n" + } + }, + "88-R02b": { + "files": { + "index.ts": "/// \nconst a: ABC = { abc: 1 };\nconst b: string = libValue;\nconst c: number = libBad;\nconst d: string = libFn(1, 2);\nconst e: string = new LibClass().m();\nconst f: string = new LibClass().p;\nwindow.localStorage;\nconst sentinel: number = \"\";\n", + "node_modules/@typescript/lib-dom/index.js": "/** @typedef {{ abc: string }} ABC */\nvar libValue = 1;\n/** @type {string} */\nvar libBad = 2;\nfunction libFn(a, b) { return a + b + missingName; }\nclass LibClass { constructor() { this.p = 1; } m() { return this.p.nope; } }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"target\": \"es2015\", \"libReplacement\": true, \"noEmit\": true, \"strict\": true, \"types\": [], \"allowJs\": true, \"checkJs\": true, \"skipLibCheck\": true }, \"files\": [\"index.ts\"] }\n" + } + }, + "88-R04a": { + "files": { + "index.ts": "declare const arr: number[]; declare const ro: readonly number[]; declare const tup: [number, number]; declare const un: number[] | boolean[];\nconst [e1] = arr;\nconst [e2, ...r2] = ro;\nconst [e3] = tup;\nconst [e3b] = un;\nconst [] = arr;\nlet e4: number; [e4] = arr;\nfunction f5([a, b]: number[], [c]: [number]) {}\nfunction f6(t: T) { const [x] = t; }\nfor (const [k] of [arr]) {}\nconst { p: [q] } = { p: arr };\nconst [[n1]] = [arr];\nconst [d1 = 1] = arr;\ntry {} catch ([z]) {}\nconst sentinel: number = \"\";\n", + "node_modules/@typescript/lib-es2015/iterable.d.ts": "/*! *****************************************************************************\nCopyright (c) Microsoft Corporation. All rights reserved.\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nthis file except in compliance with the License. You may obtain a copy of the\nLicense at http://www.apache.org/licenses/LICENSE-2.0\n\nTHIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\nKIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED\nWARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,\nMERCHANTABILITY OR NON-INFRINGEMENT.\n\nSee the Apache Version 2.0 License for specific language governing permissions\nand limitations under the License.\n***************************************************************************** */\n\n\n/// \n\ninterface SymbolConstructor {\n /**\n * A method that returns the default iterator for an object. Called by the semantics of the\n * for-of statement.\n */\n readonly iterator: unique symbol;\n}\n\ninterface IteratorYieldResult {\n done?: false;\n value: TYield;\n}\n\ninterface IteratorReturnResult {\n done: true;\n value: TReturn;\n}\n\ntype IteratorResult = IteratorYieldResult | IteratorReturnResult;\n\ninterface Iterator {\n // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.\n next(...[value]: [] | [TNext]): IteratorResult;\n return?(value?: TReturn): IteratorResult;\n throw?(e?: any): IteratorResult;\n}\n\ninterface Iterable {\n [Symbol.iterator](): Iterator;\n}\n\n/**\n * Describes a user-defined {@link Iterator} that is also iterable.\n */\ninterface IterableIterator extends Iterator {\n [Symbol.iterator](): IterableIterator;\n}\n\n/**\n * Describes an {@link Iterator} produced by the runtime that inherits from the intrinsic `Iterator.prototype`.\n */\ninterface IteratorObject extends Iterator {\n [Symbol.iterator](): IteratorObject;\n}\n\n/**\n * Defines the `TReturn` type used for built-in iterators produced by `Array`, `Map`, `Set`, and others.\n * This is `undefined` when `strictBuiltInIteratorReturn` is `true`; otherwise, this is `any`.\n */\ntype BuiltinIteratorReturn = intrinsic;\n\ninterface ArrayIterator extends IteratorObject {\n}\n\ninterface Array {\n /** Iterator */\n\n /**\n * Returns an iterable of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, T]>;\n\n /**\n * Returns an iterable of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an iterable of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface ArrayConstructor {\n /**\n * Creates an array from an iterable object.\n * @param iterable An iterable object to convert to an array.\n */\n from(iterable: Iterable | ArrayLike): T[];\n\n /**\n * Creates an array from an iterable object.\n * @param iterable An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[];\n}\n\ninterface ReadonlyArray {\n /** Iterator of values in the array. */\n [Symbol.iterator](): ArrayIterator;\n\n /**\n * Returns an iterable of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, T]>;\n\n /**\n * Returns an iterable of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an iterable of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface IArguments {\n /** Iterator */\n [Symbol.iterator](): ArrayIterator;\n}\n\ninterface MapIterator extends IteratorObject {\n [Symbol.iterator](): MapIterator;\n}\n\ninterface Map {\n /** Returns an iterable of entries in the map. */\n [Symbol.iterator](): MapIterator<[K, V]>;\n\n /**\n * Returns an iterable of key, value pairs for every entry in the map.\n */\n entries(): MapIterator<[K, V]>;\n\n /**\n * Returns an iterable of keys in the map\n */\n keys(): MapIterator;\n\n /**\n * Returns an iterable of values in the map\n */\n values(): MapIterator;\n}\n\ninterface ReadonlyMap {\n /** Returns an iterable of entries in the map. */\n [Symbol.iterator](): MapIterator<[K, V]>;\n\n /**\n * Returns an iterable of key, value pairs for every entry in the map.\n */\n entries(): MapIterator<[K, V]>;\n\n /**\n * Returns an iterable of keys in the map\n */\n keys(): MapIterator;\n\n /**\n * Returns an iterable of values in the map\n */\n values(): MapIterator;\n}\n\ninterface MapConstructor {\n new (): Map;\n new (iterable?: Iterable | null): Map;\n}\n\ninterface WeakMap {}\n\ninterface WeakMapConstructor {\n new (iterable?: Iterable | null): WeakMap;\n}\n\ninterface SetIterator extends IteratorObject {\n [Symbol.iterator](): SetIterator;\n}\n\ninterface Set {\n /** Iterates over values in the set. */\n [Symbol.iterator](): SetIterator;\n\n /**\n * Returns an iterable of [v,v] pairs for every value `v` in the set.\n */\n entries(): SetIterator<[T, T]>;\n\n /**\n * Despite its name, returns an iterable of the values in the set.\n */\n keys(): SetIterator;\n\n /**\n * Returns an iterable of values in the set.\n */\n values(): SetIterator;\n}\n\ninterface ReadonlySet {\n /** Iterates over values in the set. */\n [Symbol.iterator](): SetIterator;\n\n /**\n * Returns an iterable of [v,v] pairs for every value `v` in the set.\n */\n entries(): SetIterator<[T, T]>;\n\n /**\n * Despite its name, returns an iterable of the values in the set.\n */\n keys(): SetIterator;\n\n /**\n * Returns an iterable of values in the set.\n */\n values(): SetIterator;\n}\n\ninterface SetConstructor {\n new (iterable?: Iterable | null): Set;\n}\n\ninterface WeakSet {}\n\ninterface WeakSetConstructor {\n new (iterable: Iterable): WeakSet;\n}\n\ninterface Promise {}\n\ninterface PromiseConstructor {\n /**\n * Creates a Promise that is resolved with an array of results when all of the provided Promises\n * resolve, or rejected when any Promise is rejected.\n * @param values An iterable of Promises.\n * @returns A new Promise.\n */\n all(values: Iterable>): Promise[]>;\n\n /**\n * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved\n * or rejected.\n * @param values An iterable of Promises.\n * @returns A new Promise.\n */\n race(values: Iterable>): Promise>;\n}\n\ninterface StringIterator extends IteratorObject {\n [Symbol.iterator](): StringIterator;\n}\n\ninterface String {\n /** Iterator */\n [Symbol.iterator](): StringIterator;\n}\n\ninterface Int8Array {\n [Symbol.iterator](): ArrayIterator;\n\n /**\n * Returns an array of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, number]>;\n\n /**\n * Returns an list of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an list of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface Int8ArrayConstructor {\n new (elements: Iterable): Int8Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n */\n from(elements: Iterable): Int8Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(elements: Iterable, mapfn?: (v: T, k: number) => number, thisArg?: any): Int8Array;\n}\n\ninterface Uint8Array {\n [Symbol.iterator](): ArrayIterator;\n\n /**\n * Returns an array of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, number]>;\n\n /**\n * Returns an list of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an list of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface Uint8ArrayConstructor {\n new (elements: Iterable): Uint8Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n */\n from(elements: Iterable): Uint8Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(elements: Iterable, mapfn?: (v: T, k: number) => number, thisArg?: any): Uint8Array;\n}\n\ninterface Uint8ClampedArray {\n [Symbol.iterator](): ArrayIterator;\n\n /**\n * Returns an array of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, number]>;\n\n /**\n * Returns an list of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an list of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface Uint8ClampedArrayConstructor {\n new (elements: Iterable): Uint8ClampedArray;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n */\n from(elements: Iterable): Uint8ClampedArray;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(elements: Iterable, mapfn?: (v: T, k: number) => number, thisArg?: any): Uint8ClampedArray;\n}\n\ninterface Int16Array {\n [Symbol.iterator](): ArrayIterator;\n /**\n * Returns an array of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, number]>;\n\n /**\n * Returns an list of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an list of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface Int16ArrayConstructor {\n new (elements: Iterable): Int16Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n */\n from(elements: Iterable): Int16Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(elements: Iterable, mapfn?: (v: T, k: number) => number, thisArg?: any): Int16Array;\n}\n\ninterface Uint16Array {\n [Symbol.iterator](): ArrayIterator;\n\n /**\n * Returns an array of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, number]>;\n\n /**\n * Returns an list of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an list of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface Uint16ArrayConstructor {\n new (elements: Iterable): Uint16Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n */\n from(elements: Iterable): Uint16Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(elements: Iterable, mapfn?: (v: T, k: number) => number, thisArg?: any): Uint16Array;\n}\n\ninterface Int32Array {\n [Symbol.iterator](): ArrayIterator;\n\n /**\n * Returns an array of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, number]>;\n\n /**\n * Returns an list of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an list of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface Int32ArrayConstructor {\n new (elements: Iterable): Int32Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n */\n from(elements: Iterable): Int32Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(elements: Iterable, mapfn?: (v: T, k: number) => number, thisArg?: any): Int32Array;\n}\n\ninterface Uint32Array {\n [Symbol.iterator](): ArrayIterator;\n\n /**\n * Returns an array of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, number]>;\n\n /**\n * Returns an list of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an list of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface Uint32ArrayConstructor {\n new (elements: Iterable): Uint32Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n */\n from(elements: Iterable): Uint32Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(elements: Iterable, mapfn?: (v: T, k: number) => number, thisArg?: any): Uint32Array;\n}\n\ninterface Float32Array {\n [Symbol.iterator](): ArrayIterator;\n\n /**\n * Returns an array of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, number]>;\n\n /**\n * Returns an list of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an list of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface Float32ArrayConstructor {\n new (elements: Iterable): Float32Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n */\n from(elements: Iterable): Float32Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(elements: Iterable, mapfn?: (v: T, k: number) => number, thisArg?: any): Float32Array;\n}\n\ninterface Float64Array {\n [Symbol.iterator](): ArrayIterator;\n\n /**\n * Returns an array of key, value pairs for every entry in the array\n */\n entries(): ArrayIterator<[number, number]>;\n\n /**\n * Returns an list of keys in the array\n */\n keys(): ArrayIterator;\n\n /**\n * Returns an list of values in the array\n */\n values(): ArrayIterator;\n}\n\ninterface Float64ArrayConstructor {\n new (elements: Iterable): Float64Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n */\n from(elements: Iterable): Float64Array;\n\n /**\n * Creates an array from an array-like or iterable object.\n * @param elements An iterable object to convert to an array.\n * @param mapfn A mapping function to call on every element of the array.\n * @param thisArg Value of 'this' used to invoke the mapfn.\n */\n from(elements: Iterable, mapfn?: (v: T, k: number) => number, thisArg?: any): Float64Array;\n}\n", + "tsconfig.json": "{ \"compilerOptions\": { \"target\": \"es2015\", \"libReplacement\": true, \"skipDefaultLibCheck\": true, \"noEmit\": true, \"strict\": true } }\n" + } + }, + "88-R04b": { + "files": { + "a.ts": "interface Array {}\ninterface Object {}\ninterface Function {}\ninterface String {}\ninterface Number {}\ninterface Boolean {}\ninterface RegExp {}\ninterface IArguments {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface Symbol {}\ninterface SymbolConstructor { readonly iterator: unique symbol; }\ndeclare var Symbol: SymbolConstructor;\ninterface Iterator { next(): { done: boolean; value: T }; }\ninterface Iterable { [Symbol.iterator](): Iterator; }\ninterface ReadonlyArray {}\ndeclare const arr: number[]; declare const ro: readonly number[]; declare const tup: [number, number];\nconst [e1] = arr;\nconst [e2, ...r2] = ro;\nconst [e3] = tup;\nconst [] = arr;\nlet e4: number; [e4] = arr;\nfunction f5([a, b]: number[], [c]: [number]) {}\nconst { p: [q] } = { p: arr };\nconst [d1 = 1] = arr;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"noLib\": true } }\n" + } + }, + "88-R05a": { + "files": { + "a.ts": "export {};\ntype Keys = \"a\" | \"b\";\nclass C1 { [k: string]: any; [P in Keys]: number }\nclass C2 { static [k: string]: any; static [P in Keys]: number }\nclass C3 { [k: string]: any; [P in Keys]?: number }\nclass C4 { [k: string]: any; readonly [P in Keys]: number }\nclass C5 { [k: number]: any; [P in Keys]() {} }\nclass C6 { [k: symbol]: any; get [P in Keys]() { return 1 } }\nconst E7 = class { [k: string]: any; [P in Keys]: number };\ndeclare class C8 { [k: string]: any; [P in Keys]: number }\nabstract class C9 { [k: string]: any; abstract [P in Keys]: number }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "88-R05b": { + "files": { + "a.ts": "export {};\nfunction f1() {\n const kk = \"x\"; const oo = {};\n class D1 { [k: string]: any; [kk in oo]: number = 1 }\n return D1;\n}\nfunction f2() {\n const kk = \"x\"; const oo = {};\n class D2 { [kk in oo]: number = 1 }\n return D2;\n}\nclass D3 { [k: string]: any; [later in laterObj]: number = 1 }\nconst later = \"x\"; const laterObj = {};\nclass D4 { [k: string]: any; [missing1.a.b in missing2()]: number = 1 }\nclass D5 { [k: string]: any; [(missing3) in [missing4]]: number = 1 }\nclass D6 { [k: string]: any; [this.x in super.y]: number = 1 }\nclass D7 { [k: string]: any; [T in T]: number = 1 }\nfunction f8(this: any, arg: string) { return class { [k: string]: any; [arg in this]: number = 1 } }\nimport { gone } from \"./gone\";\nclass D9 { [k: string]: any; [gone in gone]: number = 1 }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noUnusedLocals\": true } }\n" + } + }, + "88-R08a": { + "files": { + "a.js": "/** @type {typeof globalThis.} */ var v8 = \"x\";\n/** @type {number} */ const sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true, \"module\": \"esnext\", \"target\": \"es2022\" } }\n" + } + }, + "88-R18": { + "files": { + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"rootDir\": \"./xꟌ\", \"types\": [], \"lib\": [\"es2022\"]}, \"files\": [\"xꟍ/a.ts\"]}", + "xꟍ/a.ts": "const sentinel: number = \"\";\n" + } + }, + "88-R19a": { + "files": { + "node_modules/dep/index.d.ts": "import { T } from \"./internal\";\nexport declare function f(): T;\n", + "node_modules/dep/internal.d.ts": "export interface T { a: 1 }\n", + "node_modules/dep/package.json": "{\"name\": \"dep\", \"version\": \"1.0.0\", \"exports\": {\".\": \"./index.d.ts\"}}", + "package.json": "{\"name\": \"p\", \"dependencies\": {\"dep\": \"*\"}}", + "src/a.ts": "import { f } from \"dep\";\nexport const x = f();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"declaration\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"paths\": {\"@/*\": [\"./*\"]}}, \"files\": [\"src/a.ts\"]}" + } + }, + "88-R19b": { + "files": { + "a.ts": "import { f } from \"dep\";\nexport const x = f();\nconst sentinel: number = \"\";\n", + "node_modules/dep/index.d.ts": "import { T } from \"./internal\";\nexport declare function f(): T;\n", + "node_modules/dep/internal.d.ts": "export interface T { a: 1 }\n", + "node_modules/dep/package.json": "{\"name\": \"dep\", \"version\": \"1.0.0\", \"exports\": {\".\": \"./index.d.ts\"}}", + "package.json": "{ \"name\": \"p\", \"imports\": { \"#app/*\": \"./*\" } }\n", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"declaration\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\"}, \"files\": [\"a.ts\"]}" + } + }, + "88-R19c": { + "files": { + "node_modules/dep/index.d.ts": "import { T } from \"./internal\";\nexport declare function f(): T;\n", + "node_modules/dep/internal.d.ts": "export interface T { a: 1 }\n", + "node_modules/dep/package.json": "{\"name\": \"dep\", \"version\": \"1.0.0\", \"exports\": {\".\": \"./index.d.ts\"}}", + "package.json": "{\"name\": \"p\", \"imports\": {\"#app/*\": \"./*\"}}", + "sub/a.ts": "import { f } from \"dep\";\nexport const x = f();\nconst sentinel: number = \"\";\n", + "sub/package.json": "{\"dependencies\": {\"dep\": \"*\"}, \"imports\": {\"#up/*\": \"../*\"}}", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"declaration\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\"}, \"files\": [\"sub/a.ts\"]}" + } + }, + "89-R08": { + "files": { + "a.ts": "const all: 0 = [fromF, fromG, fromH];\nconst sentinel: number = \"\";\n", + "node_modules/@types/f:/index.d.ts": "declare const fromF: \"f\";\n", + "node_modules/@types/g/index.d.ts": "declare const fromG: \"g\";\n", + "roots/h:/index.d.ts": "declare const fromH: \"h\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"lib\": [\"es2022\"], \"types\": [\"*\"], \"typeRoots\": [\"node_modules/@types\", \"roots\"] }, \"files\": [\"a.ts\"] }\n" + } + }, + "89-R12e": { + "files": { + "j.js": "class J { constructor() { this.a = /** @type {\"b\"} */ (\"b\"); this[jk] = 1; } }\n/** @type {J[\"a\"]} */\nconst jk = \"b\";\nnew J().b;\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "89-R13": { + "files": { + "a.ts": "// 1 an independent late name first: it starts the binding (getLateBoundSymbol), the key after it is typed in the meantime\ndeclare const j1: \"x\";\nclass C1 { a: \"b\" = \"b\"; [j1]: string = \"\"; [k1]: number = 1 }\ndeclare const k1: C1[\"a\"];\nnew C1().x; new C1().b; new C1().a;\n// 2 the circular key first\ndeclare const j2: \"x\";\nclass C2 { a: \"b\" = \"b\"; [k2]: number = 1; [j2]: string = \"\" }\ndeclare const k2: C2[\"a\"];\nnew C2().x; new C2().b; new C2().a;\n// 3 unique symbol first\ndeclare const s3: unique symbol;\nclass C3 { a: \"b\" = \"b\"; [s3]: string = \"\"; [k3]: number = 1 }\ndeclare const k3: C3[\"a\"];\nnew C3()[s3]; new C3().b;\n// 4 Symbol.iterator first\nclass C4 { a: \"b\" = \"b\"; *[Symbol.iterator]() { yield 1; } [k4]: number = 1 }\ndeclare const k4: C4[\"a\"];\nfor (const x of new C4()) {} new C4().b;\n// 5 static side\ndeclare const j5: \"x\";\nclass C5 { static a: \"b\" = \"b\"; static [j5]: string = \"\"; static [k5]: number = 1 }\ndeclare const k5: (typeof C5)[\"a\"];\nC5.x; C5.b;\n// 6 interface\ndeclare const j6: \"x\";\ninterface I6 { a: \"b\"; [j6]: string; [k6]: number }\ndeclare const k6: I6[\"a\"];\ndeclare const i6: I6; i6.x; i6.b;\n// 7 declare class\ndeclare const j7: \"x\";\ndeclare class C7 { a: \"b\"; [j7]: string; [k7]: number }\ndeclare const k7: C7[\"a\"];\nnew C7().x; new C7().b;\n// 8 subclass sees it?\ndeclare const j8: \"x\";\nclass C8 { a: \"b\" = \"b\"; [j8]: string = \"\"; [k8]: number = 1 }\ndeclare const k8: C8[\"a\"];\nclass D8 extends C8 {}\nnew D8().x; new D8().b;\n// 9 generic class, other instantiation\ndeclare const j9: \"x\";\nclass C9 { a: \"b\" = \"b\"; [j9]: string = \"\"; [k9]: number = 1; t!: T }\ndeclare const k9: C9<1>[\"a\"];\nnew C9<1>().x; new C9<2>().x; new C9<2>().b;\n// 10 type of `this` inside\ndeclare const j10: \"x\";\nclass C10 { a: \"b\" = \"b\"; [j10]: string = \"\"; [k10]: number = 1; m() { this.x; this.b; } }\ndeclare const k10: C10[\"a\"];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "89-R14": { + "files": { + "a.ts": "declare function base(x: T): new () => { v: T };\n// checkConditionalExpression tests the condition for TS2774 / TS2801 at once: it asks for the call signatures of its type.\ndeclare const x1: C1;\nconst k1 = x1 ? \"a\" : \"b\";\nclass C1 extends base(k1) {}\n// nested in the condition, nullable, in an arrow function\ndeclare const x2: C2 | undefined, y2: boolean;\nconst k2 = (y2 && x2) ? \"a\" : \"b\";\nclass C2 extends base(k2) {}\ndeclare const x3: C3;\nconst k3 = (() => x3 ? \"a\" : \"b\")();\nclass C3 extends base(k3) {}\n// an interface\ndeclare const x4: I4;\nconst k4 = x4 ? \"a\" : \"b\";\ninterface I4 extends Array {}\n// a late-bound name\ndeclare const x5: I5;\nconst k5 = x5 ? \"a\" : \"a\";\ninterface I5 { [k5]: number }\n// `&&`, `||`, `!`: the two agree\ndeclare const x6: C6;\nconst k6 = x6 && \"a\";\nclass C6 extends base(k6) {}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "89-R15": { + "files": { + "a.ts": "class U {\n #p = 1;\n m(x: U | { [k: string]: string }, y: { [k: string]: string }, z: U & { [k: string]: string }, w: U | Record, t: U | [string]) {\n const r1: never = x.#p;\n const r2: never = y.#p;\n const r3: never = z.#p;\n const r4: never = w.#p;\n const r5: never = t.#p;\n x.#p = 1;\n x.#p = \"\";\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "89-R18b": { + "files": { + "a.ts": "import { a1 } from \"./v\";\nexport interface I1 extends Array {}\nexport declare class Base { inherited: T }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n", + "v.ts": "// Before a.ts in program order: tsc types the variable first, as with the variable above the interface in one file. No TS2339.\nimport type { I1 } from \"./a\";\ndeclare const i1: I1;\nexport const a1 = i1.length;\n" + } + }, + "89-R19": { + "files": { + "a.js": "Object.defineProperty(exports, \"g1\", { get() { return exports.g1; } });\nObject.defineProperty(exports, \"g2\", { get: () => exports.g2 });\nObject.defineProperty(exports, \"g3\", { get: () => { return exports.g3; } });\nObject.defineProperty(exports, \"g4\", { get: function () { return exports.g4; } });\nObject.defineProperty(exports, \"g5\", { get: function named() { return exports.g5; } });\nObject.defineProperty(exports, \"g6\", { get() { return exports.g7; } });\nObject.defineProperty(exports, \"g7\", { get() { return exports.g6; } });\nObject.defineProperty(exports, \"v1\", { value: () => exports.v1 });\nObject.defineProperty(exports, \"v2\", { value() { return exports.v2; } });\nObject.defineProperty(module.exports, \"g8\", { get() { return module.exports.g8; } });\nfunction F() {}\nObject.defineProperty(F, \"g9\", { get() { return F.g9; } });\nObject.defineProperty(F.prototype, \"g10\", { get() { return new F().g10; } });\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\" } }\n" + } + }, + "89-R20": { + "files": { + "a.ts": "interface Options { a?: number }\ndeclare const defaults: Options;\ndeclare function take(o: Options): void;\n// Valid in tsc: getSpreadSymbol makes a NEW symbol, without a value declaration, for a get-only accessor (it is read-only, the copy is not).\nconst o1: Options = { ...defaults, get extra() { return 1; } };\nconst o2: Options = { get extra() { return 1; }, ...defaults };\ntake({ ...defaults, get extra() { return 1; } });\nconst o3: { n: Options }[] = [{ n: { ...defaults, get extra() { return 1; } } }];\nfunction ret(): Options { return { ...defaults, get extra() { return 1; } }; }\nconst o4: Readonly = { ...defaults, get extra() { return 1; } };\n// another error in place of TS2353\nconst o5: Options = { ...{}, get extra() { return 1; } };\nconst o6: { b: number } = { ...defaults, get extra() { return 1; } };\n// the two agree: TS2353 for a property, a method, a getter with a setter; none for a setter alone\nconst p1: Options = { ...defaults, extra: 1 };\nconst p2: Options = { ...defaults, extra() {} };\nconst p3: Options = { ...defaults, get extra() { return 1; }, set extra(v) {} };\nconst p4: Options = { ...defaults, set extra(v: number) {} };\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "90-R06": { + "files": { + "a.ts": "import { which } from \"cond9000\"; const x: 0 = which;\nconst sentinel: number = \"\";\n", + "node_modules/cond9000/index.d.ts": "export declare const which: \"index\";\n", + "node_modules/cond9000/package.json": "{\"types\":\"u.d.ts\",\"exports\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":\"./t.d.ts\"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", + "node_modules/cond9000/t.d.ts": "export declare const which: \"t\";\n", + "node_modules/cond9000/u.d.ts": "export declare const which: \"u\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"a.ts\"] }\n" + }, + "deep": true + }, + "90-R09": { + "files": { + "a.ts": "interface U2 extends U1, U3 {}\ninterface U1 extends U2 {}\ninterface U3 { m(): this }\ndeclare const u1: U1;\nconst k1: number = u1.m();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "90-R10a": { + "files": { + "a.ts": "import { G1 as GC, G1 as GN } from \"./t\";\nimport c = GC.v;\nimport d = GN.nope;\nc; d;\nexport const sentinel: number = \"\";\n", + "g.d.ts": "declare class GC { static v: number }\ndeclare namespace GN { const v: number }\n", + "t.ts": "export interface G1 { x: 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"isolatedModules\": true, \"esModuleInterop\": true } }\n" + } + }, + "90-R10b": { + "files": { + "a.ts": "import c = K.v; c; class K { static v = 1 }\nimport d = L.v; d; let L = { v: 1 };\nimport e = En.X.y; e; enum En { X }\nimport type { G1 as TO } from \"./t\";\nimport f = TO.v; f;\nfunction fn(p = g) { } import g = P.v; const P = { v: 1 };\nexport const sentinel: number = \"\";\n", + "t.ts": "export interface Reflect { x: 1 }\nexport interface Intl { x: 1 }\nexport interface G1 { x: 1 }\nexport interface G2 { x: 1 }\nexport interface G3 { x: 1 }\nexport interface G4 { x: 1 }\nexport interface G5 { x: 1 }\nexport interface G6 { x: 1 }\nexport interface G7 { x: 1 }\nexport interface G8 { x: 1 }\nexport type G9 = 1;\nexport default interface GD { x: 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"target\": \"es2022\", \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"isolatedModules\": true, \"esModuleInterop\": true } }\n" + } + }, + "90-R16": { + "files": { + "a.ts": "namespace A0.A1.A2.A3.A4.A5.A6.A7.A8.A9.A10.A11.A12.A13.A14.A15.A16.A17.A18.A19.A20.A21.A22.A23.A24.A25.A26.A27.A28.A29.A30.A31.A32.A33.A34.A35.A36.A37.A38.A39.A40.A41.A42.A43.A44.A45.A46.A47.A48.A49.A50.A51.A52.A53.A54.A55.A56.A57.A58.A59.A60.A61.A62.A63.A64.A65.A66.A67.A68.A69.A70.A71.A72.A73.A74.A75.A76.A77.A78.A79.A80.A81.A82.A83.A84.A85.A86.A87.A88.A89.A90.A91.A92.A93.A94.A95.A96.A97.A98.A99.A100.A101.A102.A103.A104.A105.A106.A107.A108.A109.A110.A111.A112.A113.A114.A115.A116.A117.A118.A119.A120.A121.A122.A123.A124.A125.A126.A127.A128.A129.A130.A131.A132.A133.A134.A135.A136.A137.A138.A139.A140.A141.A142.A143.A144.A145.A146.A147.A148.A149.A150.A151.A152.A153.A154.A155.A156.A157.A158.A159.A160.A161.A162.A163.A164.A165.A166.A167.A168.A169.A170.A171.A172.A173.A174.A175.A176.A177.A178.A179.A180.A181.A182.A183.A184.A185.A186.A187.A188.A189.A190.A191.A192.A193.A194.A195.A196.A197.A198.A199.A200.A201.A202.A203.A204.A205.A206.A207.A208.A209.A210.A211.A212.A213.A214.A215.A216.A217.A218.A219.A220.A221.A222.A223.A224.A225.A226.A227.A228.A229.A230.A231.A232.A233.A234.A235.A236.A237.A238.A239.A240.A241.A242.A243.A244.A245.A246.A247.A248.A249.A250.A251.A252.A253.A254.A255.A256.A257.A258.A259.A260.A261.A262.A263.A264.A265.A266.A267.A268.A269.A270.A271.A272.A273.A274.A275.A276.A277.A278.A279.A280.A281.A282.A283.A284.A285.A286.A287.A288.A289.A290.A291.A292.A293.A294.A295.A296.A297.A298.A299.A300.A301.A302.A303.A304.A305.A306.A307.A308.A309.A310.A311.A312.A313.A314.A315.A316.A317.A318.A319.A320.A321.A322.A323.A324.A325.A326.A327.A328.A329.A330.A331.A332.A333.A334.A335.A336.A337.A338.A339.A340.A341.A342.A343.A344.A345.A346.A347.A348.A349.A350.A351.A352.A353.A354.A355.A356.A357.A358.A359.A360.A361.A362.A363.A364.A365.A366.A367.A368.A369.A370.A371.A372.A373.A374.A375.A376.A377.A378.A379.A380.A381.A382.A383.A384.A385.A386.A387.A388.A389.A390.A391.A392.A393.A394.A395.A396.A397.A398.A399.A400.A401.A402.A403.A404.A405.A406.A407.A408.A409.A410.A411.A412.A413.A414.A415.A416.A417.A418.A419.A420.A421.A422.A423.A424.A425.A426.A427.A428.A429.A430.A431.A432.A433.A434.A435.A436.A437.A438.A439.A440.A441.A442.A443.A444.A445.A446.A447.A448.A449.A450.A451.A452.A453.A454.A455.A456.A457.A458.A459.A460.A461.A462.A463.A464.A465.A466.A467.A468.A469.A470.A471.A472.A473.A474.A475.A476.A477.A478.A479.A480.A481.A482.A483.A484.A485.A486.A487.A488.A489.A490.A491.A492.A493.A494.A495.A496.A497.A498.A499.A500.A501.A502.A503.A504.A505.A506.A507.A508.A509.A510.A511.A512.A513.A514.A515.A516.A517.A518.A519.A520.A521.A522.A523.A524.A525.A526.A527.A528.A529.A530.A531.A532.A533.A534.A535.A536.A537.A538.A539.A540.A541.A542.A543.A544.A545.A546.A547.A548.A549.A550.A551.A552.A553.A554.A555.A556.A557.A558.A559.A560.A561.A562.A563.A564.A565.A566.A567.A568.A569.A570.A571.A572.A573.A574.A575.A576.A577.A578.A579.A580.A581.A582.A583.A584.A585.A586.A587.A588.A589.A590.A591.A592.A593.A594.A595.A596.A597.A598.A599.A600.A601.A602.A603.A604.A605.A606.A607.A608.A609.A610.A611.A612.A613.A614.A615.A616.A617.A618.A619.A620.A621.A622.A623.A624.A625.A626.A627.A628.A629.A630.A631.A632.A633.A634.A635.A636.A637.A638.A639.A640.A641.A642.A643.A644.A645.A646.A647.A648.A649.A650.A651.A652.A653.A654.A655.A656.A657.A658.A659.A660.A661.A662.A663.A664.A665.A666.A667.A668.A669.A670.A671.A672.A673.A674.A675.A676.A677.A678.A679.A680.A681.A682.A683.A684.A685.A686.A687.A688.A689.A690.A691.A692.A693.A694.A695.A696.A697.A698.A699.A700.A701.A702.A703.A704.A705.A706.A707.A708.A709.A710.A711.A712.A713.A714.A715.A716.A717.A718.A719.A720.A721.A722.A723.A724.A725.A726.A727.A728.A729.A730.A731.A732.A733.A734.A735.A736.A737.A738.A739.A740.A741.A742.A743.A744.A745.A746.A747.A748.A749.A750.A751.A752.A753.A754.A755.A756.A757.A758.A759.A760.A761.A762.A763.A764.A765.A766.A767.A768.A769.A770.A771.A772.A773.A774.A775.A776.A777.A778.A779.A780.A781.A782.A783.A784.A785.A786.A787.A788.A789.A790.A791.A792.A793.A794.A795.A796.A797.A798.A799.A800.A801.A802.A803.A804.A805.A806.A807.A808.A809.A810.A811.A812.A813.A814.A815.A816.A817.A818.A819.A820.A821.A822.A823.A824.A825.A826.A827.A828.A829.A830.A831.A832.A833.A834.A835.A836.A837.A838.A839.A840.A841.A842.A843.A844.A845.A846.A847.A848.A849.A850.A851.A852.A853.A854.A855.A856.A857.A858.A859.A860.A861.A862.A863.A864.A865.A866.A867.A868.A869.A870.A871.A872.A873.A874.A875.A876.A877.A878.A879.A880.A881.A882.A883.A884.A885.A886.A887.A888.A889.A890.A891.A892.A893.A894.A895.A896.A897.A898.A899.A900.A901.A902.A903.A904.A905.A906.A907.A908.A909.A910.A911.A912.A913.A914.A915.A916.A917.A918.A919.A920.A921.A922.A923.A924.A925.A926.A927.A928.A929.A930.A931.A932.A933.A934.A935.A936.A937.A938.A939.A940.A941.A942.A943.A944.A945.A946.A947.A948.A949.A950.A951.A952.A953.A954.A955.A956.A957.A958.A959.A960.A961.A962.A963.A964.A965.A966.A967.A968.A969.A970.A971.A972.A973.A974.A975.A976.A977.A978.A979.A980.A981.A982.A983.A984.A985.A986.A987.A988.A989.A990.A991.A992.A993.A994.A995.A996.A997.A998.A999.A1000.A1001.A1002.A1003.A1004.A1005.A1006.A1007.A1008.A1009.A1010.A1011.A1012.A1013.A1014.A1015.A1016.A1017.A1018.A1019.A1020.A1021.A1022.A1023.A1024.A1025.A1026.A1027.A1028.A1029.A1030.A1031.A1032.A1033.A1034.A1035.A1036.A1037.A1038.A1039.A1040.A1041.A1042.A1043.A1044.A1045.A1046.A1047.A1048.A1049.A1050.A1051.A1052.A1053.A1054.A1055.A1056.A1057.A1058.A1059.A1060.A1061.A1062.A1063.A1064.A1065.A1066.A1067.A1068.A1069.A1070.A1071.A1072.A1073.A1074.A1075.A1076.A1077.A1078.A1079.A1080.A1081.A1082.A1083.A1084.A1085.A1086.A1087.A1088.A1089.A1090.A1091.A1092.A1093.A1094.A1095.A1096.A1097.A1098.A1099.A1100.A1101.A1102.A1103.A1104.A1105.A1106.A1107.A1108.A1109.A1110.A1111.A1112.A1113.A1114.A1115.A1116.A1117.A1118.A1119.A1120.A1121.A1122.A1123.A1124.A1125.A1126.A1127.A1128.A1129.A1130.A1131.A1132.A1133.A1134.A1135.A1136.A1137.A1138.A1139.A1140.A1141.A1142.A1143.A1144.A1145.A1146.A1147.A1148.A1149.A1150.A1151.A1152.A1153.A1154.A1155.A1156.A1157.A1158.A1159.A1160.A1161.A1162.A1163.A1164.A1165.A1166.A1167.A1168.A1169.A1170.A1171.A1172.A1173.A1174.A1175.A1176.A1177.A1178.A1179.A1180.A1181.A1182.A1183.A1184.A1185.A1186.A1187.A1188.A1189.A1190.A1191.A1192.A1193.A1194.A1195.A1196.A1197.A1198.A1199.A1200.A1201.A1202.A1203.A1204.A1205.A1206.A1207.A1208.A1209.A1210.A1211.A1212.A1213.A1214.A1215.A1216.A1217.A1218.A1219.A1220.A1221.A1222.A1223.A1224.A1225.A1226.A1227.A1228.A1229.A1230.A1231.A1232.A1233.A1234.A1235.A1236.A1237.A1238.A1239.A1240.A1241.A1242.A1243.A1244.A1245.A1246.A1247.A1248.A1249.A1250.A1251.A1252.A1253.A1254.A1255.A1256.A1257.A1258.A1259.A1260.A1261.A1262.A1263.A1264.A1265.A1266.A1267.A1268.A1269.A1270.A1271.A1272.A1273.A1274.A1275.A1276.A1277.A1278.A1279.A1280.A1281.A1282.A1283.A1284.A1285.A1286.A1287.A1288.A1289.A1290.A1291.A1292.A1293.A1294.A1295.A1296.A1297.A1298.A1299.A1300.A1301.A1302.A1303.A1304.A1305.A1306.A1307.A1308.A1309.A1310.A1311.A1312.A1313.A1314.A1315.A1316.A1317.A1318.A1319.A1320.A1321.A1322.A1323.A1324.A1325.A1326.A1327.A1328.A1329.A1330.A1331.A1332.A1333.A1334.A1335.A1336.A1337.A1338.A1339.A1340.A1341.A1342.A1343.A1344.A1345.A1346.A1347.A1348.A1349.A1350.A1351.A1352.A1353.A1354.A1355.A1356.A1357.A1358.A1359.A1360.A1361.A1362.A1363.A1364.A1365.A1366.A1367.A1368.A1369.A1370.A1371.A1372.A1373.A1374.A1375.A1376.A1377.A1378.A1379.A1380.A1381.A1382.A1383.A1384.A1385.A1386.A1387.A1388.A1389.A1390.A1391.A1392.A1393.A1394.A1395.A1396.A1397.A1398.A1399.A1400.A1401.A1402.A1403.A1404.A1405.A1406.A1407.A1408.A1409.A1410.A1411.A1412.A1413.A1414.A1415.A1416.A1417.A1418.A1419.A1420.A1421.A1422.A1423.A1424.A1425.A1426.A1427.A1428.A1429.A1430.A1431.A1432.A1433.A1434.A1435.A1436.A1437.A1438.A1439.A1440.A1441.A1442.A1443.A1444.A1445.A1446.A1447.A1448.A1449.A1450.A1451.A1452.A1453.A1454.A1455.A1456.A1457.A1458.A1459.A1460.A1461.A1462.A1463.A1464.A1465.A1466.A1467.A1468.A1469.A1470.A1471.A1472.A1473.A1474.A1475.A1476.A1477.A1478.A1479.A1480.A1481.A1482.A1483.A1484.A1485.A1486.A1487.A1488.A1489.A1490.A1491.A1492.A1493.A1494.A1495.A1496.A1497.A1498.A1499.A1500.A1501.A1502.A1503.A1504.A1505.A1506.A1507.A1508.A1509.A1510.A1511.A1512.A1513.A1514.A1515.A1516.A1517.A1518.A1519.A1520.A1521.A1522.A1523.A1524.A1525.A1526.A1527.A1528.A1529.A1530.A1531.A1532.A1533.A1534.A1535.A1536.A1537.A1538.A1539.A1540.A1541.A1542.A1543.A1544.A1545.A1546.A1547.A1548.A1549.A1550.A1551.A1552.A1553.A1554.A1555.A1556.A1557.A1558.A1559.A1560.A1561.A1562.A1563.A1564.A1565.A1566.A1567.A1568.A1569.A1570.A1571.A1572.A1573.A1574.A1575.A1576.A1577.A1578.A1579.A1580.A1581.A1582.A1583.A1584.A1585.A1586.A1587.A1588.A1589.A1590.A1591.A1592.A1593.A1594.A1595.A1596.A1597.A1598.A1599.A1600.A1601.A1602.A1603.A1604.A1605.A1606.A1607.A1608.A1609.A1610.A1611.A1612.A1613.A1614.A1615.A1616.A1617.A1618.A1619.A1620.A1621.A1622.A1623.A1624.A1625.A1626.A1627.A1628.A1629.A1630.A1631.A1632.A1633.A1634.A1635.A1636.A1637.A1638.A1639.A1640.A1641.A1642.A1643.A1644.A1645.A1646.A1647.A1648.A1649.A1650.A1651.A1652.A1653.A1654.A1655.A1656.A1657.A1658.A1659.A1660.A1661.A1662.A1663.A1664.A1665.A1666.A1667.A1668.A1669.A1670.A1671.A1672.A1673.A1674.A1675.A1676.A1677.A1678.A1679.A1680.A1681.A1682.A1683.A1684.A1685.A1686.A1687.A1688.A1689.A1690.A1691.A1692.A1693.A1694.A1695.A1696.A1697.A1698.A1699.A1700.A1701.A1702.A1703.A1704.A1705.A1706.A1707.A1708.A1709.A1710.A1711.A1712.A1713.A1714.A1715.A1716.A1717.A1718.A1719.A1720.A1721.A1722.A1723.A1724.A1725.A1726.A1727.A1728.A1729.A1730.A1731.A1732.A1733.A1734.A1735.A1736.A1737.A1738.A1739.A1740.A1741.A1742.A1743.A1744.A1745.A1746.A1747.A1748.A1749.A1750.A1751.A1752.A1753.A1754.A1755.A1756.A1757.A1758.A1759.A1760.A1761.A1762.A1763.A1764.A1765.A1766.A1767.A1768.A1769.A1770.A1771.A1772.A1773.A1774.A1775.A1776.A1777.A1778.A1779.A1780.A1781.A1782.A1783.A1784.A1785.A1786.A1787.A1788.A1789.A1790.A1791.A1792.A1793.A1794.A1795.A1796.A1797.A1798.A1799.A1800.A1801.A1802.A1803.A1804.A1805.A1806.A1807.A1808.A1809.A1810.A1811.A1812.A1813.A1814.A1815.A1816.A1817.A1818.A1819.A1820.A1821.A1822.A1823.A1824.A1825.A1826.A1827.A1828.A1829.A1830.A1831.A1832.A1833.A1834.A1835.A1836.A1837.A1838.A1839.A1840.A1841.A1842.A1843.A1844.A1845.A1846.A1847.A1848.A1849.A1850.A1851.A1852.A1853.A1854.A1855.A1856.A1857.A1858.A1859.A1860.A1861.A1862.A1863.A1864.A1865.A1866.A1867.A1868.A1869.A1870.A1871.A1872.A1873.A1874.A1875.A1876.A1877.A1878.A1879.A1880.A1881.A1882.A1883.A1884.A1885.A1886.A1887.A1888.A1889.A1890.A1891.A1892.A1893.A1894.A1895.A1896.A1897.A1898.A1899.A1900.A1901.A1902.A1903.A1904.A1905.A1906.A1907.A1908.A1909.A1910.A1911.A1912.A1913.A1914.A1915.A1916.A1917.A1918.A1919.A1920.A1921.A1922.A1923.A1924.A1925.A1926.A1927.A1928.A1929.A1930.A1931.A1932.A1933.A1934.A1935.A1936.A1937.A1938.A1939.A1940.A1941.A1942.A1943.A1944.A1945.A1946.A1947.A1948.A1949.A1950.A1951.A1952.A1953.A1954.A1955.A1956.A1957.A1958.A1959.A1960.A1961.A1962.A1963.A1964.A1965.A1966.A1967.A1968.A1969.A1970.A1971.A1972.A1973.A1974.A1975.A1976.A1977.A1978.A1979.A1980.A1981.A1982.A1983.A1984.A1985.A1986.A1987.A1988.A1989.A1990.A1991.A1992.A1993.A1994.A1995.A1996.A1997.A1998.A1999 { export class C { x = 1 } }\nconst v = new A0.A1.A2.A3.A4.A5.A6.A7.A8.A9.A10.A11.A12.A13.A14.A15.A16.A17.A18.A19.A20.A21.A22.A23.A24.A25.A26.A27.A28.A29.A30.A31.A32.A33.A34.A35.A36.A37.A38.A39.A40.A41.A42.A43.A44.A45.A46.A47.A48.A49.A50.A51.A52.A53.A54.A55.A56.A57.A58.A59.A60.A61.A62.A63.A64.A65.A66.A67.A68.A69.A70.A71.A72.A73.A74.A75.A76.A77.A78.A79.A80.A81.A82.A83.A84.A85.A86.A87.A88.A89.A90.A91.A92.A93.A94.A95.A96.A97.A98.A99.A100.A101.A102.A103.A104.A105.A106.A107.A108.A109.A110.A111.A112.A113.A114.A115.A116.A117.A118.A119.A120.A121.A122.A123.A124.A125.A126.A127.A128.A129.A130.A131.A132.A133.A134.A135.A136.A137.A138.A139.A140.A141.A142.A143.A144.A145.A146.A147.A148.A149.A150.A151.A152.A153.A154.A155.A156.A157.A158.A159.A160.A161.A162.A163.A164.A165.A166.A167.A168.A169.A170.A171.A172.A173.A174.A175.A176.A177.A178.A179.A180.A181.A182.A183.A184.A185.A186.A187.A188.A189.A190.A191.A192.A193.A194.A195.A196.A197.A198.A199.A200.A201.A202.A203.A204.A205.A206.A207.A208.A209.A210.A211.A212.A213.A214.A215.A216.A217.A218.A219.A220.A221.A222.A223.A224.A225.A226.A227.A228.A229.A230.A231.A232.A233.A234.A235.A236.A237.A238.A239.A240.A241.A242.A243.A244.A245.A246.A247.A248.A249.A250.A251.A252.A253.A254.A255.A256.A257.A258.A259.A260.A261.A262.A263.A264.A265.A266.A267.A268.A269.A270.A271.A272.A273.A274.A275.A276.A277.A278.A279.A280.A281.A282.A283.A284.A285.A286.A287.A288.A289.A290.A291.A292.A293.A294.A295.A296.A297.A298.A299.A300.A301.A302.A303.A304.A305.A306.A307.A308.A309.A310.A311.A312.A313.A314.A315.A316.A317.A318.A319.A320.A321.A322.A323.A324.A325.A326.A327.A328.A329.A330.A331.A332.A333.A334.A335.A336.A337.A338.A339.A340.A341.A342.A343.A344.A345.A346.A347.A348.A349.A350.A351.A352.A353.A354.A355.A356.A357.A358.A359.A360.A361.A362.A363.A364.A365.A366.A367.A368.A369.A370.A371.A372.A373.A374.A375.A376.A377.A378.A379.A380.A381.A382.A383.A384.A385.A386.A387.A388.A389.A390.A391.A392.A393.A394.A395.A396.A397.A398.A399.A400.A401.A402.A403.A404.A405.A406.A407.A408.A409.A410.A411.A412.A413.A414.A415.A416.A417.A418.A419.A420.A421.A422.A423.A424.A425.A426.A427.A428.A429.A430.A431.A432.A433.A434.A435.A436.A437.A438.A439.A440.A441.A442.A443.A444.A445.A446.A447.A448.A449.A450.A451.A452.A453.A454.A455.A456.A457.A458.A459.A460.A461.A462.A463.A464.A465.A466.A467.A468.A469.A470.A471.A472.A473.A474.A475.A476.A477.A478.A479.A480.A481.A482.A483.A484.A485.A486.A487.A488.A489.A490.A491.A492.A493.A494.A495.A496.A497.A498.A499.A500.A501.A502.A503.A504.A505.A506.A507.A508.A509.A510.A511.A512.A513.A514.A515.A516.A517.A518.A519.A520.A521.A522.A523.A524.A525.A526.A527.A528.A529.A530.A531.A532.A533.A534.A535.A536.A537.A538.A539.A540.A541.A542.A543.A544.A545.A546.A547.A548.A549.A550.A551.A552.A553.A554.A555.A556.A557.A558.A559.A560.A561.A562.A563.A564.A565.A566.A567.A568.A569.A570.A571.A572.A573.A574.A575.A576.A577.A578.A579.A580.A581.A582.A583.A584.A585.A586.A587.A588.A589.A590.A591.A592.A593.A594.A595.A596.A597.A598.A599.A600.A601.A602.A603.A604.A605.A606.A607.A608.A609.A610.A611.A612.A613.A614.A615.A616.A617.A618.A619.A620.A621.A622.A623.A624.A625.A626.A627.A628.A629.A630.A631.A632.A633.A634.A635.A636.A637.A638.A639.A640.A641.A642.A643.A644.A645.A646.A647.A648.A649.A650.A651.A652.A653.A654.A655.A656.A657.A658.A659.A660.A661.A662.A663.A664.A665.A666.A667.A668.A669.A670.A671.A672.A673.A674.A675.A676.A677.A678.A679.A680.A681.A682.A683.A684.A685.A686.A687.A688.A689.A690.A691.A692.A693.A694.A695.A696.A697.A698.A699.A700.A701.A702.A703.A704.A705.A706.A707.A708.A709.A710.A711.A712.A713.A714.A715.A716.A717.A718.A719.A720.A721.A722.A723.A724.A725.A726.A727.A728.A729.A730.A731.A732.A733.A734.A735.A736.A737.A738.A739.A740.A741.A742.A743.A744.A745.A746.A747.A748.A749.A750.A751.A752.A753.A754.A755.A756.A757.A758.A759.A760.A761.A762.A763.A764.A765.A766.A767.A768.A769.A770.A771.A772.A773.A774.A775.A776.A777.A778.A779.A780.A781.A782.A783.A784.A785.A786.A787.A788.A789.A790.A791.A792.A793.A794.A795.A796.A797.A798.A799.A800.A801.A802.A803.A804.A805.A806.A807.A808.A809.A810.A811.A812.A813.A814.A815.A816.A817.A818.A819.A820.A821.A822.A823.A824.A825.A826.A827.A828.A829.A830.A831.A832.A833.A834.A835.A836.A837.A838.A839.A840.A841.A842.A843.A844.A845.A846.A847.A848.A849.A850.A851.A852.A853.A854.A855.A856.A857.A858.A859.A860.A861.A862.A863.A864.A865.A866.A867.A868.A869.A870.A871.A872.A873.A874.A875.A876.A877.A878.A879.A880.A881.A882.A883.A884.A885.A886.A887.A888.A889.A890.A891.A892.A893.A894.A895.A896.A897.A898.A899.A900.A901.A902.A903.A904.A905.A906.A907.A908.A909.A910.A911.A912.A913.A914.A915.A916.A917.A918.A919.A920.A921.A922.A923.A924.A925.A926.A927.A928.A929.A930.A931.A932.A933.A934.A935.A936.A937.A938.A939.A940.A941.A942.A943.A944.A945.A946.A947.A948.A949.A950.A951.A952.A953.A954.A955.A956.A957.A958.A959.A960.A961.A962.A963.A964.A965.A966.A967.A968.A969.A970.A971.A972.A973.A974.A975.A976.A977.A978.A979.A980.A981.A982.A983.A984.A985.A986.A987.A988.A989.A990.A991.A992.A993.A994.A995.A996.A997.A998.A999.A1000.A1001.A1002.A1003.A1004.A1005.A1006.A1007.A1008.A1009.A1010.A1011.A1012.A1013.A1014.A1015.A1016.A1017.A1018.A1019.A1020.A1021.A1022.A1023.A1024.A1025.A1026.A1027.A1028.A1029.A1030.A1031.A1032.A1033.A1034.A1035.A1036.A1037.A1038.A1039.A1040.A1041.A1042.A1043.A1044.A1045.A1046.A1047.A1048.A1049.A1050.A1051.A1052.A1053.A1054.A1055.A1056.A1057.A1058.A1059.A1060.A1061.A1062.A1063.A1064.A1065.A1066.A1067.A1068.A1069.A1070.A1071.A1072.A1073.A1074.A1075.A1076.A1077.A1078.A1079.A1080.A1081.A1082.A1083.A1084.A1085.A1086.A1087.A1088.A1089.A1090.A1091.A1092.A1093.A1094.A1095.A1096.A1097.A1098.A1099.A1100.A1101.A1102.A1103.A1104.A1105.A1106.A1107.A1108.A1109.A1110.A1111.A1112.A1113.A1114.A1115.A1116.A1117.A1118.A1119.A1120.A1121.A1122.A1123.A1124.A1125.A1126.A1127.A1128.A1129.A1130.A1131.A1132.A1133.A1134.A1135.A1136.A1137.A1138.A1139.A1140.A1141.A1142.A1143.A1144.A1145.A1146.A1147.A1148.A1149.A1150.A1151.A1152.A1153.A1154.A1155.A1156.A1157.A1158.A1159.A1160.A1161.A1162.A1163.A1164.A1165.A1166.A1167.A1168.A1169.A1170.A1171.A1172.A1173.A1174.A1175.A1176.A1177.A1178.A1179.A1180.A1181.A1182.A1183.A1184.A1185.A1186.A1187.A1188.A1189.A1190.A1191.A1192.A1193.A1194.A1195.A1196.A1197.A1198.A1199.A1200.A1201.A1202.A1203.A1204.A1205.A1206.A1207.A1208.A1209.A1210.A1211.A1212.A1213.A1214.A1215.A1216.A1217.A1218.A1219.A1220.A1221.A1222.A1223.A1224.A1225.A1226.A1227.A1228.A1229.A1230.A1231.A1232.A1233.A1234.A1235.A1236.A1237.A1238.A1239.A1240.A1241.A1242.A1243.A1244.A1245.A1246.A1247.A1248.A1249.A1250.A1251.A1252.A1253.A1254.A1255.A1256.A1257.A1258.A1259.A1260.A1261.A1262.A1263.A1264.A1265.A1266.A1267.A1268.A1269.A1270.A1271.A1272.A1273.A1274.A1275.A1276.A1277.A1278.A1279.A1280.A1281.A1282.A1283.A1284.A1285.A1286.A1287.A1288.A1289.A1290.A1291.A1292.A1293.A1294.A1295.A1296.A1297.A1298.A1299.A1300.A1301.A1302.A1303.A1304.A1305.A1306.A1307.A1308.A1309.A1310.A1311.A1312.A1313.A1314.A1315.A1316.A1317.A1318.A1319.A1320.A1321.A1322.A1323.A1324.A1325.A1326.A1327.A1328.A1329.A1330.A1331.A1332.A1333.A1334.A1335.A1336.A1337.A1338.A1339.A1340.A1341.A1342.A1343.A1344.A1345.A1346.A1347.A1348.A1349.A1350.A1351.A1352.A1353.A1354.A1355.A1356.A1357.A1358.A1359.A1360.A1361.A1362.A1363.A1364.A1365.A1366.A1367.A1368.A1369.A1370.A1371.A1372.A1373.A1374.A1375.A1376.A1377.A1378.A1379.A1380.A1381.A1382.A1383.A1384.A1385.A1386.A1387.A1388.A1389.A1390.A1391.A1392.A1393.A1394.A1395.A1396.A1397.A1398.A1399.A1400.A1401.A1402.A1403.A1404.A1405.A1406.A1407.A1408.A1409.A1410.A1411.A1412.A1413.A1414.A1415.A1416.A1417.A1418.A1419.A1420.A1421.A1422.A1423.A1424.A1425.A1426.A1427.A1428.A1429.A1430.A1431.A1432.A1433.A1434.A1435.A1436.A1437.A1438.A1439.A1440.A1441.A1442.A1443.A1444.A1445.A1446.A1447.A1448.A1449.A1450.A1451.A1452.A1453.A1454.A1455.A1456.A1457.A1458.A1459.A1460.A1461.A1462.A1463.A1464.A1465.A1466.A1467.A1468.A1469.A1470.A1471.A1472.A1473.A1474.A1475.A1476.A1477.A1478.A1479.A1480.A1481.A1482.A1483.A1484.A1485.A1486.A1487.A1488.A1489.A1490.A1491.A1492.A1493.A1494.A1495.A1496.A1497.A1498.A1499.A1500.A1501.A1502.A1503.A1504.A1505.A1506.A1507.A1508.A1509.A1510.A1511.A1512.A1513.A1514.A1515.A1516.A1517.A1518.A1519.A1520.A1521.A1522.A1523.A1524.A1525.A1526.A1527.A1528.A1529.A1530.A1531.A1532.A1533.A1534.A1535.A1536.A1537.A1538.A1539.A1540.A1541.A1542.A1543.A1544.A1545.A1546.A1547.A1548.A1549.A1550.A1551.A1552.A1553.A1554.A1555.A1556.A1557.A1558.A1559.A1560.A1561.A1562.A1563.A1564.A1565.A1566.A1567.A1568.A1569.A1570.A1571.A1572.A1573.A1574.A1575.A1576.A1577.A1578.A1579.A1580.A1581.A1582.A1583.A1584.A1585.A1586.A1587.A1588.A1589.A1590.A1591.A1592.A1593.A1594.A1595.A1596.A1597.A1598.A1599.A1600.A1601.A1602.A1603.A1604.A1605.A1606.A1607.A1608.A1609.A1610.A1611.A1612.A1613.A1614.A1615.A1616.A1617.A1618.A1619.A1620.A1621.A1622.A1623.A1624.A1625.A1626.A1627.A1628.A1629.A1630.A1631.A1632.A1633.A1634.A1635.A1636.A1637.A1638.A1639.A1640.A1641.A1642.A1643.A1644.A1645.A1646.A1647.A1648.A1649.A1650.A1651.A1652.A1653.A1654.A1655.A1656.A1657.A1658.A1659.A1660.A1661.A1662.A1663.A1664.A1665.A1666.A1667.A1668.A1669.A1670.A1671.A1672.A1673.A1674.A1675.A1676.A1677.A1678.A1679.A1680.A1681.A1682.A1683.A1684.A1685.A1686.A1687.A1688.A1689.A1690.A1691.A1692.A1693.A1694.A1695.A1696.A1697.A1698.A1699.A1700.A1701.A1702.A1703.A1704.A1705.A1706.A1707.A1708.A1709.A1710.A1711.A1712.A1713.A1714.A1715.A1716.A1717.A1718.A1719.A1720.A1721.A1722.A1723.A1724.A1725.A1726.A1727.A1728.A1729.A1730.A1731.A1732.A1733.A1734.A1735.A1736.A1737.A1738.A1739.A1740.A1741.A1742.A1743.A1744.A1745.A1746.A1747.A1748.A1749.A1750.A1751.A1752.A1753.A1754.A1755.A1756.A1757.A1758.A1759.A1760.A1761.A1762.A1763.A1764.A1765.A1766.A1767.A1768.A1769.A1770.A1771.A1772.A1773.A1774.A1775.A1776.A1777.A1778.A1779.A1780.A1781.A1782.A1783.A1784.A1785.A1786.A1787.A1788.A1789.A1790.A1791.A1792.A1793.A1794.A1795.A1796.A1797.A1798.A1799.A1800.A1801.A1802.A1803.A1804.A1805.A1806.A1807.A1808.A1809.A1810.A1811.A1812.A1813.A1814.A1815.A1816.A1817.A1818.A1819.A1820.A1821.A1822.A1823.A1824.A1825.A1826.A1827.A1828.A1829.A1830.A1831.A1832.A1833.A1834.A1835.A1836.A1837.A1838.A1839.A1840.A1841.A1842.A1843.A1844.A1845.A1846.A1847.A1848.A1849.A1850.A1851.A1852.A1853.A1854.A1855.A1856.A1857.A1858.A1859.A1860.A1861.A1862.A1863.A1864.A1865.A1866.A1867.A1868.A1869.A1870.A1871.A1872.A1873.A1874.A1875.A1876.A1877.A1878.A1879.A1880.A1881.A1882.A1883.A1884.A1885.A1886.A1887.A1888.A1889.A1890.A1891.A1892.A1893.A1894.A1895.A1896.A1897.A1898.A1899.A1900.A1901.A1902.A1903.A1904.A1905.A1906.A1907.A1908.A1909.A1910.A1911.A1912.A1913.A1914.A1915.A1916.A1917.A1918.A1919.A1920.A1921.A1922.A1923.A1924.A1925.A1926.A1927.A1928.A1929.A1930.A1931.A1932.A1933.A1934.A1935.A1936.A1937.A1938.A1939.A1940.A1941.A1942.A1943.A1944.A1945.A1946.A1947.A1948.A1949.A1950.A1951.A1952.A1953.A1954.A1955.A1956.A1957.A1958.A1959.A1960.A1961.A1962.A1963.A1964.A1965.A1966.A1967.A1968.A1969.A1970.A1971.A1972.A1973.A1974.A1975.A1976.A1977.A1978.A1979.A1980.A1981.A1982.A1983.A1984.A1985.A1986.A1987.A1988.A1989.A1990.A1991.A1992.A1993.A1994.A1995.A1996.A1997.A1998.A1999.C();\nconst bad: number = v;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + }, + "deep": true + }, + "90-R17a": { + "files": { + "a.ts": "export {};\ndeclare const key: string; declare const dec: any; declare function use(...a: any[]): void;\nexport @dec class P { static y = 1; [key] = class { static x = 1 } }\nconst sentinel: number = \"\";\n", + "b.ts": "export {};\ndeclare const key: string; declare const dec: any; declare function use(...a: any[]): void;\nexport default @dec class P { static y = 1; [key] = class { static x = 1 } }\nconst sentinel: number = \"\";\n", + "node_modules/tslib/index.d.ts": "export declare function __nothing(): void;\n", + "node_modules/tslib/package.json": "{ \"name\": \"tslib\", \"version\": \"2.0.0\", \"types\": \"index.d.ts\" }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"esnext.decorators\"], \"importHelpers\": true, \"target\": \"es2022\", \"useDefineForClassFields\": false, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "90-R17b": { + "files": { + "a1.ts": "import { late } from \"./b1\"; export const u = new late();\n", + "b1.ts": "@dec class X { static y = 1 } import { u } from \"./a1\"; declare const dec: any; u;\nexport const first = class { static x = 1 }; export const late = class { static x = 2 };\nconst sentinel: number = \"\";\n", + "node_modules/tslib/index.d.ts": "export declare function __nothing(): void;\n", + "node_modules/tslib/package.json": "{ \"name\": \"tslib\", \"version\": \"2.0.0\", \"types\": \"index.d.ts\" }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"esnext.decorators\"], \"importHelpers\": true, \"target\": \"es2022\", \"useDefineForClassFields\": false, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"b1.ts\"] }\n" + } + }, + "90-R17c": { + "files": { + "a5.ts": "import { mk } from \"./b5\"; export const u = mk();\n", + "b5.ts": "const zero = class { static x = 0 }; import { u } from \"./a5\"; u;\nexport function mk() { const k = class { static x = 1 }; return new k(); }\nconst sentinel: number = \"\";\n", + "node_modules/tslib/index.d.ts": "export declare function __nothing(): void;\n", + "node_modules/tslib/package.json": "{ \"name\": \"tslib\", \"version\": \"2.0.0\", \"types\": \"index.d.ts\" }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\", \"esnext.decorators\"], \"importHelpers\": true, \"target\": \"es2022\", \"useDefineForClassFields\": false, \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"b5.ts\"] }\n" + } + }, + "91-R01": { + "files": { + "a.ts": "declare let y: any;\ndeclare let s: string;\n(s = 1) = y;\n[(s = 1)] = y;\n({ a: (s = 1) } = y);\nfor ((s = 1) of y) {}\n({ a: ({ b: s } = { b: 1 }) } = y);\n({ a: ({ k() {} } = y) } = y);\n[s = 1] = y;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "91-R02": { + "files": { + "a.tsx": "declare namespace JSX { interface Element {} interface IntrinsicElements { div: any } }\ndeclare const React: any;\nconst enum E { A = 1 }\nlet j1 =
;\nlet j2 =
{E}
;\nlet j3 =
;\nlet j4 =
;\nlet j5 =
{E.A}
;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"react\" } }\n" + } + }, + "91-R05a": { + "files": { + "a.ts": "type as = number;\ntype satisfies = T;\nnamespace satisfies { export const y = 1; }\nnamespace N { interface as { a: number } }\nfunction f() { type as = 1; let x: as = 1; return x; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "91-R09": { + "files": { + "a.js": "/** @type {unknown} */\nconst v = null;\n/** @param {unknown} x @returns {(asserts x is string)} */\nfunction p1(x) {}\nfunction t1() { p1(v); v.length; }\nclass K {\n /** @returns {(asserts this is L)} */\n n() {}\n}\nclass L extends K { l = 1 }\n/** @type {K} */\nconst k = new K();\nfunction t2() { k.n(); k.l; }\n/** @param {unknown} x @returns {(asserts x is string)} */\nconst p3 = x => {};\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + } + }, + "91-R12a": { + "files": { + "a.ts": "import { C, v } from \"./m\";\ndeclare const o: any;\nconst local1 = 1;\nfunction fn1() {}\nwith (o) { var a1 = new C(), a2 = v + local1, a3 = fn1(); }\na1; a2; a3;\nwith (o) { var a4 = function (x: number, z: number) { let q = 1, r = 2; return x + q; }; }\na4;\nexport const sentinel: number = \"\";\n", + "m.ts": "export class C {} export const v = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"noUnusedLocals\": true, \"noUnusedParameters\": true } }\n" + } + }, + "91-R12b": { + "files": { + "a.ts": "declare const o: any;\nwith (o) { var a1 = 1; }\nwith (o) { var [a2, ...a3] = o; }\nwith (o) { namespace a4 {} }\nfunction f() { with (o) { var b1 = 1; let b2 = 2; } }\nf();\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"noUnusedLocals\": true, \"noUnusedParameters\": true } }\n" + } + }, + "91-R12c": { + "files": { + "a.js": "var o = /** @type {any} */ (null);\nwith (o) { var r1 = require(\"./nope1\"); }\nr1;\nwith (o) { var { r2 } = require(\"./nope2\"); }\nr2;\nwith (o) { var r3 = require(\"./nope3\"); }\n/** @type {number} */\nvar sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\" } }\n" + } + }, + "91-R12d": { + "files": { + "a.js": "var o = /** @type {any} */ (null);\nwith (o) { exports.z8 = missing8; module.exports.z9 = missing9; exports.z10 = missing10 + 1; }\nzzzzzzzzzzzz;\n/** @type {number} */\nvar sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\" } }\n" + } + }, + "92-R02a": { + "files": { + "a.ts": "declare const a: any, b: any, x: any, f: any; (a?.!);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "92-R02b": { + "files": { + "a.ts": "declare const a: any, b: any, x: any, f: any; (a?..b);\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "92-R02c": { + "files": { + "a.ts": "declare const a: any, b: any, x: any, f: any; x = { p: a?.!b };\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "92-R02d": { + "files": { + "a.ts": "declare const a: any, b: any, x: any, f: any; x = `${a?.!}`;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "92-R02e": { + "files": { + "a.ts": "declare const a: any, b: any, x: any, f: any; x = a[b?.!];\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "92-R02f": { + "files": { + "a.ts": "declare const a: any, b: any, x: any, f: any; x = class { p = a?.! }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "92-R02g": { + "files": { + "a.ts": "declare const a: any, b: any, T: any; a?.b;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "92-R02h": { + "files": { + "a.ts": "declare const a: any, b: any, T: any; a?.`x`;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "92-R03a": { + "files": { + "a.js": "async function f() {\n/** @import await from \"./b\" */\n/** @type {await} */\nconst x = 1;\n}\n/** @type {number} */\nconst sentinel = \"\";\n", + "b.ts": "export default interface D { d: 1 }\nexport interface A { a: 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R03b": { + "files": { + "a.js": "function* f() {\n/** @import yield from \"./b\" */\n/** @type {yield} */\nconst x = 1;\n}\n/** @type {number} */\nconst sentinel = \"\";\n", + "b.ts": "export default interface D { d: 1 }\nexport interface A { a: 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R03c": { + "files": { + "a.js": "async function f(\n/** @import await from \"./b\" */\np) {\n/** @type {await} */\nconst x = 1;\n}\n/** @type {number} */\nconst sentinel = \"\";\n", + "b.ts": "export default interface D { d: 1 }\nexport interface A { a: 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R03d": { + "files": { + "a.js": "async function f() {\n/** @import { A as await } from \"./b\" */\n/** @type {await} */\nconst x = 1;\n}\n/** @type {number} */\nconst sentinel = \"\";\n", + "b.ts": "export default interface D { d: 1 }\nexport interface A { a: 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R03f": { + "files": { + "a.js": "/** @import #a from \"./b\" */\n/** @type {number} */ const sentinel = \"\";\n", + "b.ts": "export default interface D { d: 1 }\nexport interface A { a: 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R07a": { + "files": { + "a.js": "/**\n * @type {{ a: 1; static\n * {}; b: 2 }}\n */\nconst o = 0;\no.a; o.b; o.nope;\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R07b": { + "files": { + "a.js": "/**\n * @param {{ a: 1; static\n * {}; b: 2 }} o\n */\nfunction f(o) { o.a; o.b; o.nope; }\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R07c": { + "files": { + "a.js": "/**\n * @typedef {{\n * \"a\": 1,\n * \"a\": 2\n * }} T\n */\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R07d": { + "files": { + "a.js": "/**\n * @typedef {(\n * a,\n * b\n * ) => 1} T\n */\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R07e": { + "files": { + "a.js": "/**\n * @typedef {Uppercase<\n * 1\n * >} T\n */\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "92-R07f": { + "files": { + "a.js": "/** @type {{ a: 1; [}} */\nconst o = 0;\no.a; o.nope;\n/** @type {number} */\nconst sentinel = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"allowJs\":true,\"checkJs\":true } }\n" } }, - "73-R01a": { + "92-R09a": { "files": { - "a.ts": "declare function c(): boolean;\nfunction minimal() {\n let y: string | number = \"\";\n while (c()) {\n if (y === 1) { }\n switch (y) { case 0: y = 0; }\n }\n}\nfunction likely(a: string[]) {\n let v: string | number = \"\";\n for (const e of a) {\n if (v === 1) { c(); }\n switch (v) {\n case 0: v = 1; break;\n case \"\": v = 0; break;\n }\n }\n}\nconst sentinel: number = \"\";\n", + "a.ts": "type IsPrim = T extends string | number ? true : false;\nclass Base { f!: F }\nclass A extends Base> { x = 1 }\nlet x: IsPrim;\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "73-R01b": { + "92-R09b": { "files": { - "a.ts": "declare function c(): boolean;\nfunction missed() {\n let x: string | 1 | boolean = \"\";\n let y: string | number = \"\";\n while (c()) {\n x;\n if (y === 1) { }\n x = y;\n if (c()) y = 0;\n }\n}\nfunction otherText() {\n let x: string | boolean = \"\";\n let y: string | number = \"\";\n while (c()) {\n x;\n if (y === 1) { }\n x = y;\n if (c()) y = 0;\n }\n}\nfunction reportedTwice() {\n let x: string | number | boolean = \"\";\n let y: string | number = \"\";\n while (c()) {\n x;\n if (y === 1) { }\n x = (y satisfies never);\n if (c()) y = 0;\n }\n}\nconst sentinel: number = \"\";\n", + "a.ts": "type IsPrim = T extends string | number ? true : false;\ninterface Base { f: F }\nlet x: IsPrim;\ninterface A extends Base> { x: number }\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "73-R01c": { + "92-R09c": { "files": { - "a.ts": "declare function c(): boolean;\ntype U = string | boolean;\nfunction afterLoop(x: U) {\n if (x) { x = true; }\n while (c()) { c(); }\n const p: number = x;\n}\nfunction afterIf(x: U) {\n if (x) { x = true; }\n if (c()) { c(); }\n const p: number = x;\n}\nfunction afterTry(x: U) {\n if (x) { x = true; }\n try { c(); } catch { }\n const p: number = x;\n}\ninterface Options { verbose?: Flag }\ntype Flag = boolean | \"auto\" | undefined;\nfunction likely(o: Options, args: string[]) {\n let verbose: Flag = o.verbose;\n if (verbose === \"auto\") { verbose = false; }\n for (const a of args) { c(); }\n const n: number = verbose;\n}\nconst sentinel: number = \"\";\n", + "a.ts": "type IsPrim = T extends string | number ? true : false;\ninterface Base { f: F }\ndeclare let a: A;\nlet u: { x: number } = a;\ninterface A extends Base> { x: number }\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "73-R01d": { + "92-R09d": { "files": { - "a.ts": "declare function c(): boolean;\ndeclare function log(v: unknown): void;\nfunction likely(tokens: string[]) {\n let current: string | null = \"\";\n let result: string | number | null = null;\n let total = 0;\n for (const t of tokens) {\n if (result !== null) log(result);\n if (current) { log(current); }\n result = current ?? 0;\n if (t === \";\") current = null;\n if (typeof result === \"number\") total += result.toFixed().length;\n }\n}\nfunction minimal() {\n let x: string | null = \"\";\n let y: string | number | null = null;\n while (c()) {\n y;\n if (x) { }\n y = x ?? 0;\n if (c()) x = null;\n const p: never = y;\n }\n}\nfunction nested() {\n let x: string | null = \"\";\n let y: string | number | null = null;\n while (y == null) {\n while (typeof x === \"string\" || c()) {\n y = x ?? 0;\n }\n if (c()) x = null;\n const p: never = y;\n }\n}\nconst sentinel: number = \"\";\n", + "a.ts": "type IsPrim = T extends string | number ? true : false;\ninterface Base { f: F }\ntype X = IsPrim;\ninterface A extends Base { x: number }\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "73-R01e": { + "92-R09e": { "files": { - "a.ts": "declare function fail(): never;\ndeclare function c(): boolean;\ndeclare function use(v: unknown): void;\ndeclare const arr: number[];\ntype U = string | number | boolean | null | undefined;\nfunction f4(x: string | number) { fail(); do { try { } finally { x.foo; } } while (true); }\nfunction f7(x: string | number) { fail(); do { try { } finally { try { x.foo; } finally { } } } while (true); }\nfunction plainLoop(x: string | number) { fail(); do { x.foo; } while (true); }\nfunction plainFinally(x: string | number) { fail(); try { } finally { x.foo; } }\n// the other way round: tsc reports TS2339 on `never` at the `o.x` of the switch, bun does not\nfunction f43(o: { x: U }) { fail(); do { try { } catch { try { } catch { use(o.x); } switch (typeof o.x) { } } } while (c() && o.x == null); if (typeof o.x === \"boolean\") { } }\n// `arr`, a global constant, is `never` in bun (TS2488), not in tsc\nfunction f140(o: { n: { x: U; y: U } }) { try { fail(); } finally { switch (typeof o.n.y) { case \"boolean\": do { } while (typeof o.n.x === \"boolean\"); for (const e of arr) { } } } for (const e of arr) { } }\nconst sentinel: number = \"\";\n", + "a.ts": "interface Other { o: 1 } interface Base { b: 1 } interface Sub extends Base { }\ntype Cond = T extends string | number ? { y: 1 } : { z: 1 };\ndeclare const B: new () => Cond;\nclass A extends B { x = 1 }\ndeclare const a: A; a.x; a.y; a.z;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }" + } + }, + "92-R09f": { + "files": { + "a.ts": "type IsPrim = T extends string | number ? true : false;\ninterface Base { f: F }\nlet x: IsPrim;\ninterface A extends Base> { x: number }\ninterface B extends Base> { y: number }\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "73-R03c": { + "92-R09g": { "files": { - "a.ts": "declare function c(): boolean;\nfunction f() {\n let x = []; const y = [];\n while (c()) {\n do {\n if (x.length) { for (y.push(0); (x = []); ) { } }\n else { if (x === y) return; }\n } while (x.push(1));\n }\n}\nconst sentinel: number = \"\";\n", + "a.ts": "type Primitive = string | number | boolean | bigint | symbol | null | undefined;\ntype Json = T extends Primitive ? T : { [K in keyof T]: Json };\nclass Model { declare shape: Shape; toJSON(): Shape { return this.shape; } }\nclass User extends Model> { name = \"\"; age = 0; }\nclass Post extends Model> { author = new User(); }\nconst u = new User().toJSON(); const n: number = u.name;\nconst p = new Post().toJSON().author.age; const q: string = p;\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "73-R09": { + "92-R11a": { "files": { - "a.ts": "declare function keys(o: Record): K[];\ndeclare function f2(x: { [P in K]: X }): [K, X];\nfunction strict(rw: R & W, wv: W & V, wo: W & { c: 3 }) {\n const k1: \"a\"[] = keys(rw);\n const k2: (\"a\" | \"b\")[] = keys(wv);\n const k3: (\"a\" | \"c\")[] = keys(wo);\n const p1: never = f2(rw);\n const p2: never = f2(wv);\n const p3: never = f2(wo);\n}\nconst sentinel: number = \"\";\n", + "a.ts": "type D = 0|1|2|3|4|5|6|7|8|9;\ntype G = `${Y}${Y}${Y}${Y}${Y}${Y}${X}`;\ndeclare function f(x?: any): T;\ndeclare function tag(s: TemplateStringsArray): T;\ndeclare class K { k: T }\ndeclare const e: any;\ninterface IG { g: T }\nclass C33 implements IG> { g = e }\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }" + } + }, + "92-R11b": { + "files": { + "a.ts": "type T1 = [0,0,0,0,0,0,0,0,0,0]; type T2 = [...T1,...T1,...T1,...T1,...T1,...T1,...T1,...T1,...T1,...T1]; type T3 = [...T2,...T2,...T2,...T2,...T2,...T2,...T2,...T2,...T2,...T2];\ntype G = [...Y,...Y,...Y,...Y,...Y,...Y,...Y,...Y,...Y,...Y, X];\ndeclare function f(x?: any): T;\ndeclare function tag(s: TemplateStringsArray): T;\ndeclare class K { k: T }\ndeclare const e: any;\ninterface IG { g: T }\nclass C33 implements IG> { g = e }\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }" + } + }, + "92-R11c": { + "files": { + "a.ts": "type D = 0|1|2|3|4|5|6|7|8|9;\ntype G = `${Y}${Y}${Y}${Y}${Y}${Y}${X}`;\ndeclare function f(x?: any): T;\ndeclare function tag(s: TemplateStringsArray): T;\ndeclare class K { k: T }\ndeclare const e: any;\ninterface IG { g: T }\nfunction h67({ a = e as G<\"67\"> }) {}\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }" + } + }, + "92-R11d": { + "files": { + "a.ts": "type T1 = [0,0,0,0,0,0,0,0,0,0]; type T2 = [...T1,...T1,...T1,...T1,...T1,...T1,...T1,...T1,...T1,...T1]; type T3 = [...T2,...T2,...T2,...T2,...T2,...T2,...T2,...T2,...T2,...T2];\ntype G = [...Y,...Y,...Y,...Y,...Y,...Y,...Y,...Y,...Y,...Y, X];\ndeclare function f(x?: any): T;\ndeclare function tag(s: TemplateStringsArray): T;\ndeclare class K { k: T }\ndeclare const e: any;\ninterface IG { g: T }\nfunction h67({ a = e as G<\"67\"> }) {}\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }" + } + }, + "92-R11e": { + "files": { + "a.ts": "type D = 0|1|2|3|4|5|6|7|8|9;\ntype G = `${Y}${Y}${Y}${Y}${Y}${Y}${X}`;\ndeclare function f(x?: any): T;\ndeclare class K { k: T }\ndeclare const e: any;\ninterface IG { g: T }\nfunction h({ a = (p: G<\"1\">) => 1 }) {}\nexport const sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "73-R09b": { + "92-R11f": { "files": { - "a.ts": "declare function f2(x: { [P in K]: X }): [K, X];\nfunction g(ts: T & S, tw: T & W, to: T & { b: 1 }) {\n const k1: never = f2(ts);\n const k4: never = f2(tw);\n const k5: never = f2(to);\n}\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"strictNullChecks\": false, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "type D = 0|1|2|3|4|5|6|7|8|9;\ntype G = `${Y}${Y}${Y}${Y}${Y}${Y}${X}`;\ndeclare function f(x?: any): T;\ndeclare class K { k: T }\ndeclare const e: any;\ninterface IG { g: T }\nfunction h({ a = e as G<\"1\"> } = {}) {}\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "73-R13a": { + "92-R11g": { "files": { - "a.ts": "function f({ o0: { f0: n1 = () => {}, f1: n2 = () => {}, f2: n3 = () => {}, f3: n4 = () => {}, f4: n5 = () => {}, f5: n6 = () => {}, f6: n7 = () => {}, f7: n8 = () => {}, f8: n9 = () => {}, f9: n10 = () => {}, f10: n11 = () => {}, f11: n12 = () => {}, f12: n13 = () => {}, f13: n14 = () => {}, f14: n15 = () => {}, f15: n16 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o1: { f0: n17 = () => {}, f1: n18 = () => {}, f2: n19 = () => {}, f3: n20 = () => {}, f4: n21 = () => {}, f5: n22 = () => {}, f6: n23 = () => {}, f7: n24 = () => {}, f8: n25 = () => {}, f9: n26 = () => {}, f10: n27 = () => {}, f11: n28 = () => {}, f12: n29 = () => {}, f13: n30 = () => {}, f14: n31 = () => {}, f15: n32 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o2: { f0: n33 = () => {}, f1: n34 = () => {}, f2: n35 = () => {}, f3: n36 = () => {}, f4: n37 = () => {}, f5: n38 = () => {}, f6: n39 = () => {}, f7: n40 = () => {}, f8: n41 = () => {}, f9: n42 = () => {}, f10: n43 = () => {}, f11: n44 = () => {}, f12: n45 = () => {}, f13: n46 = () => {}, f14: n47 = () => {}, f15: n48 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o3: { f0: n49 = () => {}, f1: n50 = () => {}, f2: n51 = () => {}, f3: n52 = () => {}, f4: n53 = () => {}, f5: n54 = () => {}, f6: n55 = () => {}, f7: n56 = () => {}, f8: n57 = () => {}, f9: n58 = () => {}, f10: n59 = () => {}, f11: n60 = () => {}, f12: n61 = () => {}, f13: n62 = () => {}, f14: n63 = () => {}, f15: n64 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o4: { f0: n65 = () => {}, f1: n66 = () => {}, f2: n67 = () => {}, f3: n68 = () => {}, f4: n69 = () => {}, f5: n70 = () => {}, f6: n71 = () => {}, f7: n72 = () => {}, f8: n73 = () => {}, f9: n74 = () => {}, f10: n75 = () => {}, f11: n76 = () => {}, f12: n77 = () => {}, f13: n78 = () => {}, f14: n79 = () => {}, f15: n80 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o5: { f0: n81 = () => {}, f1: n82 = () => {}, f2: n83 = () => {}, f3: n84 = () => {}, f4: n85 = () => {}, f5: n86 = () => {}, f6: n87 = () => {}, f7: n88 = () => {}, f8: n89 = () => {}, f9: n90 = () => {}, f10: n91 = () => {}, f11: n92 = () => {}, f12: n93 = () => {}, f13: n94 = () => {}, f14: n95 = () => {}, f15: n96 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o6: { f0: n97 = () => {}, f1: n98 = () => {}, f2: n99 = () => {}, f3: n100 = () => {}, f4: n101 = () => {}, f5: n102 = () => {}, f6: n103 = () => {}, f7: n104 = () => {}, f8: n105 = () => {}, f9: n106 = () => {}, f10: n107 = () => {}, f11: n108 = () => {}, f12: n109 = () => {}, f13: n110 = () => {}, f14: n111 = () => {}, f15: n112 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o7: { f0: n113 = () => {}, f1: n114 = () => {}, f2: n115 = () => {}, f3: n116 = () => {}, f4: n117 = () => {}, f5: n118 = () => {}, f6: n119 = () => {}, f7: n120 = () => {}, f8: n121 = () => {}, f9: n122 = () => {}, f10: n123 = () => {}, f11: n124 = () => {}, f12: n125 = () => {}, f13: n126 = () => {}, f14: n127 = () => {}, f15: n128 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o8: { f0: n129 = () => {}, f1: n130 = () => {}, f2: n131 = () => {}, f3: n132 = () => {}, f4: n133 = () => {}, f5: n134 = () => {}, f6: n135 = () => {}, f7: n136 = () => {}, f8: n137 = () => {}, f9: n138 = () => {}, f10: n139 = () => {}, f11: n140 = () => {}, f12: n141 = () => {}, f13: n142 = () => {}, f14: n143 = () => {}, f15: n144 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o9: { f0: n145 = () => {}, f1: n146 = () => {}, f2: n147 = () => {}, f3: n148 = () => {}, f4: n149 = () => {}, f5: n150 = () => {}, f6: n151 = () => {}, f7: n152 = () => {}, f8: n153 = () => {}, f9: n154 = () => {}, f10: n155 = () => {}, f11: n156 = () => {}, f12: n157 = () => {}, f13: n158 = () => {}, f14: n159 = () => {}, f15: n160 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o10: { f0: n161 = () => {}, f1: n162 = () => {}, f2: n163 = () => {}, f3: n164 = () => {}, f4: n165 = () => {}, f5: n166 = () => {}, f6: n167 = () => {}, f7: n168 = () => {}, f8: n169 = () => {}, f9: n170 = () => {}, f10: n171 = () => {}, f11: n172 = () => {}, f12: n173 = () => {}, f13: n174 = () => {}, f14: n175 = () => {}, f15: n176 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o11: { f0: n177 = () => {}, f1: n178 = () => {}, f2: n179 = () => {}, f3: n180 = () => {}, f4: n181 = () => {}, f5: n182 = () => {}, f6: n183 = () => {}, f7: n184 = () => {}, f8: n185 = () => {}, f9: n186 = () => {}, f10: n187 = () => {}, f11: n188 = () => {}, f12: n189 = () => {}, f13: n190 = () => {}, f14: n191 = () => {}, f15: n192 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o12: { f0: n193 = () => {}, f1: n194 = () => {}, f2: n195 = () => {}, f3: n196 = () => {}, f4: n197 = () => {}, f5: n198 = () => {}, f6: n199 = () => {}, f7: n200 = () => {}, f8: n201 = () => {}, f9: n202 = () => {}, f10: n203 = () => {}, f11: n204 = () => {}, f12: n205 = () => {}, f13: n206 = () => {}, f14: n207 = () => {}, f15: n208 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o13: { f0: n209 = () => {}, f1: n210 = () => {}, f2: n211 = () => {}, f3: n212 = () => {}, f4: n213 = () => {}, f5: n214 = () => {}, f6: n215 = () => {}, f7: n216 = () => {}, f8: n217 = () => {}, f9: n218 = () => {}, f10: n219 = () => {}, f11: n220 = () => {}, f12: n221 = () => {}, f13: n222 = () => {}, f14: n223 = () => {}, f15: n224 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o14: { f0: n225 = () => {}, f1: n226 = () => {}, f2: n227 = () => {}, f3: n228 = () => {}, f4: n229 = () => {}, f5: n230 = () => {}, f6: n231 = () => {}, f7: n232 = () => {}, f8: n233 = () => {}, f9: n234 = () => {}, f10: n235 = () => {}, f11: n236 = () => {}, f12: n237 = () => {}, f13: n238 = () => {}, f14: n239 = () => {}, f15: n240 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o15: { f0: n241 = () => {}, f1: n242 = () => {}, f2: n243 = () => {}, f3: n244 = () => {}, f4: n245 = () => {}, f5: n246 = () => {}, f6: n247 = () => {}, f7: n248 = () => {}, f8: n249 = () => {}, f9: n250 = () => {}, f10: n251 = () => {}, f11: n252 = () => {}, f12: n253 = () => {}, f13: n254 = () => {}, f14: n255 = () => {}, f15: n256 = () => {} } = { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} } } = { o0: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o1: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o2: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o3: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o4: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o5: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o6: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o7: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o8: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o9: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o10: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o11: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o12: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o13: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o14: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} }, o15: { f0: () => {}, f1: () => {}, f2: () => {}, f3: () => {}, f4: () => {}, f5: () => {}, f6: () => {}, f7: () => {}, f8: () => {}, f9: () => {}, f10: () => {}, f11: () => {}, f12: () => {}, f13: () => {}, f14: () => {}, f15: () => {} } }) {}\nconst sentinel: number = \"\";\n", + "a.ts": "type M = { [K in keyof T]: M[K] };\ntype G = M[keyof T];\ndeclare function f(x?: any): T;\ndeclare function tag(s: TemplateStringsArray): T;\ndeclare class K { k: T }\ndeclare const e: any;\ninterface IG { g: T }\nconst v1 = e as G<\"1\">;\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }" + } + }, + "92-R11h": { + "files": { + "a.ts": "type M = { [K in keyof T]: M[K] };\ntype G = M[keyof T];\ndeclare function f(x?: any): T;\ndeclare function tag(s: TemplateStringsArray): T;\ndeclare class K { k: T }\ndeclare const e: any;\ninterface IG { g: T }\ninterface I34 extends IG> {}\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }" + } + }, + "92-R11i": { + "files": { + "a.ts": "type M = { [K in keyof T]: M[K] };\ntype G = M[keyof T];\ndeclare function f(x?: any): T;\ndeclare function tag(s: TemplateStringsArray): T;\ndeclare class K { k: T }\ndeclare const e: any;\ninterface IG { g: T }\nconst v29 = class { [k: string]: G<\"29\"> };\nexport const sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }" + } + }, + "92-R14a": { + "files": { + "a.ts": "import * as ns from \"./d.json\";\nimport d from \"./d.json\";\nconst n: 0 = d; const m: 0 = ns;\nconst sentinel: number = \"\";\n", + "d.json": "module.exports = { \"a\": 1 }\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"resolveJsonModule\": true, \"esModuleInterop\": true, \"module\": \"commonjs\", \"moduleResolution\": \"bundler\" } }\n" + } + }, + "92-R16b": { + "files": { + "a.ts": "type A = { [K in \"a\"]: B[K & keyof B] };\ndeclare const a: A; a.a;\nconst sentinel: number = \"\";\n", + "b.ts": "type B = { [K in \"a\"]: A[K & keyof A] };\ndeclare const b: B; b.a;\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "73-R16a": { + "92-R17a": { "files": { - "a.ts": "type J = S & { k: 1 };\nnamespace N18 { export type J = I037 & { k: 1 }; }\nnamespace N27 { export type J = I055 & { k: 1 }; }\nnamespace N36 { export type J = I073 & { k: 1 }; }\nnamespace N38 { export type J = I077 & { k: 1 }; }\nnamespace N40 { export type J = I081 & { k: 1 }; }\nnamespace N61 { export type J = I123 & { k: 1 }; }\nnamespace N77 { export type J = I155 & { k: 1 }; }\nnamespace N92 { export type J = I185 & { k: 1 }; }\nnamespace N105 { export type J = I211 & { k: 1 }; }\nnamespace N112 { export type J = I225 & { k: 1 }; }\ninterface I002 { p2: 1 }\ninterface I008 { p8: 1 }\ninterface I026 { p26: 1 }\ninterface I028 { p28: 1 }\ninterface I037 { p37: 1 }\ninterface I044 { p44: 1 }\ninterface I055 { p55: 1 }\ninterface I073 { p73: 1 }\ninterface I077 { p77: 1 }\ninterface I081 { p81: 1 }\ninterface I098 { p98: 1 }\ninterface I123 { p123: 1 }\ninterface I128 { p128: 1 }\ninterface I155 { p155: 1 }\ninterface I185 { p185: 1 }\ninterface I200 { p200: 1 }\ninterface I204 { p204: 1 }\ninterface I206 { p206: 1 }\ninterface I211 { p211: 1 }\ninterface I214 { p214: 1 }\ninterface I225 { p225: 1 }\ndeclare const v42: N27.J | N61.J | J<55, I128> | N77.J | J<19, I200> | N40.J | J<12, I214> | N38.J | N18.J | J<105, I028> | N36.J | J<106, I026> | J<16, I206> | J<70, I098> | J<17, I204> | N92.J | J<118, I002> | N105.J | J<115, I008> | J<97, I044> | N112.J;\nconst sentinel: number = \"\";\n", + "a.ts": "type Cond = T extends Partial ? { y: 1 } : { z: 1 };\ninterface A extends Cond { x: number }\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "74-R16a": { + "92-R17b": { "files": { - "a.tsx": "switch (\n<<<<<<< x\n) {}\n", - "b.tsx": "switch (\n<<<<<<< x) {}\n", - "tsconfig.json": "{ \"compilerOptions\": { \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + "a.ts": "type M = { [K in keyof T]: 1 };\ntype Cond = T extends M ? { y: 1 } : { z: 1 };\ninterface A extends Cond { x: number }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "74-R16b": { + "92-R17c": { "files": { - "a.tsx": "switch (1) { case \n<<<<<<< x\n: }\n", - "b.tsx": "switch (1) { case \n<<<<<<< x: }\n", - "tsconfig.json": "{ \"compilerOptions\": { \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + "a.ts": "type M = { [K in keyof T]: T[K] };\ntype Cond = T extends M ? { y: 1 } : { z: 1 };\ninterface A extends Cond { x: number }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "75-R07": { + "92-R19a": { "files": { - "main.ts": "import { n1 } from \"./p1\";\nn1.nope;\nconst sentinel: number = \"\";\n", - "p1.ts": "import * as n1 from \"./p2\"; export { n1 };\nexport const v1 = 1;\n", - "p10.ts": "import * as n10 from \"./p11\"; export { n10 };\nexport const v10 = 10;\n", - "p11.ts": "import * as n11 from \"./p12\"; export { n11 };\nexport const v11 = 11;\n", - "p12.ts": "import * as n12 from \"./p13\"; export { n12 };\nexport const v12 = 12;\n", - "p13.ts": "import * as n13 from \"./p14\"; export { n13 };\nexport const v13 = 13;\n", - "p14.ts": "import * as n14 from \"./p15\"; export { n14 };\nexport const v14 = 14;\n", - "p15.ts": "import * as n15 from \"./p16\"; export { n15 };\nexport const v15 = 15;\n", - "p16.ts": "import * as n16 from \"./p17\"; export { n16 };\nexport const v16 = 16;\n", - "p17.ts": "import * as n17 from \"./p18\"; export { n17 };\nexport const v17 = 17;\n", - "p18.ts": "import * as n18 from \"./p19\"; export { n18 };\nexport const v18 = 18;\n", - "p19.ts": "import * as n19 from \"./p20\"; export { n19 };\nexport const v19 = 19;\n", - "p2.ts": "import * as n2 from \"./p3\"; export { n2 };\nexport const v2 = 2;\n", - "p20.ts": "import * as n20 from \"./p21\"; export { n20 };\nexport const v20 = 20;\n", - "p21.ts": "import * as n21 from \"./p22\"; export { n21 };\nexport const v21 = 21;\n", - "p22.ts": "import * as n22 from \"./p23\"; export { n22 };\nexport const v22 = 22;\n", - "p23.ts": "import * as n23 from \"./p24\"; export { n23 };\nexport const v23 = 23;\n", - "p24.ts": "import * as n24 from \"./p25\"; export { n24 };\nexport const v24 = 24;\n", - "p25.ts": "import * as n25 from \"./p26\"; export { n25 };\nexport const v25 = 25;\n", - "p26.ts": "import * as n26 from \"./p27\"; export { n26 };\nexport const v26 = 26;\n", - "p27.ts": "import * as n27 from \"./p28\"; export { n27 };\nexport const v27 = 27;\n", - "p28.ts": "import * as n28 from \"./p29\"; export { n28 };\nexport const v28 = 28;\n", - "p29.ts": "import * as n29 from \"./p30\"; export { n29 };\nexport const v29 = 29;\n", - "p3.ts": "import * as n3 from \"./p4\"; export { n3 };\nexport const v3 = 3;\n", - "p30.ts": "import * as n30 from \"./p31\"; export { n30 };\nexport const v30 = 30;\n", - "p31.ts": "import * as n31 from \"./p32\"; export { n31 };\nexport const v31 = 31;\n", - "p32.ts": "import * as n32 from \"./p33\"; export { n32 };\nexport const v32 = 32;\n", - "p33.ts": "import * as n33 from \"./p34\"; export { n33 };\nexport const v33 = 33;\n", - "p34.ts": "import * as n34 from \"./p35\"; export { n34 };\nexport const v34 = 34;\n", - "p35.ts": "import * as n35 from \"./p36\"; export { n35 };\nexport const v35 = 35;\n", - "p36.ts": "import * as n36 from \"./p37\"; export { n36 };\nexport const v36 = 36;\n", - "p37.ts": "import * as n37 from \"./p38\"; export { n37 };\nexport const v37 = 37;\n", - "p38.ts": "import * as n38 from \"./p39\"; export { n38 };\nexport const v38 = 38;\n", - "p39.ts": "import * as n39 from \"./p40\"; export { n39 };\nexport const v39 = 39;\n", - "p4.ts": "import * as n4 from \"./p5\"; export { n4 };\nexport const v4 = 4;\n", - "p40.ts": "import * as n40 from \"./p41\"; export { n40 };\nexport const v40 = 40;\n", - "p41.ts": "import * as n41 from \"./p42\"; export { n41 };\nexport const v41 = 41;\n", - "p42.ts": "import * as n42 from \"./p43\"; export { n42 };\nexport const v42 = 42;\n", - "p43.ts": "import * as n43 from \"./p44\"; export { n43 };\nexport const v43 = 43;\n", - "p44.ts": "import * as n44 from \"./p45\"; export { n44 };\nexport const v44 = 44;\n", - "p45.ts": "import * as n45 from \"./p46\"; export { n45 };\nexport const v45 = 45;\n", - "p46.ts": "import * as n46 from \"./p47\"; export { n46 };\nexport const v46 = 46;\n", - "p47.ts": "import * as n47 from \"./p48\"; export { n47 };\nexport const v47 = 47;\n", - "p48.ts": "import * as n48 from \"./p49\"; export { n48 };\nexport const v48 = 48;\n", - "p49.ts": "import * as n49 from \"./p50\"; export { n49 };\nexport const v49 = 49;\n", - "p5.ts": "import * as n5 from \"./p6\"; export { n5 };\nexport const v5 = 5;\n", - "p50.ts": "import * as n50 from \"./p51\"; export { n50 };\nexport const v50 = 50;\n", - "p51.ts": "import * as n51 from \"./p1\"; export { n51 };\nexport const v51 = 51;\n", - "p6.ts": "import * as n6 from \"./p7\"; export { n6 };\nexport const v6 = 6;\n", - "p7.ts": "import * as n7 from \"./p8\"; export { n7 };\nexport const v7 = 7;\n", - "p8.ts": "import * as n8 from \"./p9\"; export { n8 };\nexport const v8 = 8;\n", - "p9.ts": "import * as n9 from \"./p10\"; export { n9 };\nexport const v9 = 9;\n", - "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\"}, \"files\": [\"main.ts\"]}" + "a.ts": "type S = [Extract, Extract];\nfunction f1() {} f1[0] = 1; f1[\"1\"] = 2; f1[\"1.5\"] = 3; f1[\"-1\"] = 4; f1[\"a\"] = 5;\nconst f3 = () => {}; f3[0] = 1; f3[\"1\"] = 2;\nconst t1: S = [\"?\", -99], t3: S = [\"?\", -99];\ntype M = { [K in keyof typeof f1]: K }; const m: M = 0;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "75-R07b": { + "92-R19b": { "files": { - "main.ts": "namespace M { export const v = 1; }\nimport a1 = a2;\nimport a2 = a3;\nimport a3 = a4;\nimport a4 = a5;\nimport a5 = a6;\nimport a6 = a7;\nimport a7 = a8;\nimport a8 = a9;\nimport a9 = a10;\nimport a10 = a11;\nimport a11 = a12;\nimport a12 = a13;\nimport a13 = a14;\nimport a14 = a15;\nimport a15 = a16;\nimport a16 = a17;\nimport a17 = a18;\nimport a18 = a19;\nimport a19 = a20;\nimport a20 = a21;\nimport a21 = a22;\nimport a22 = a23;\nimport a23 = a24;\nimport a24 = a25;\nimport a25 = a26;\nimport a26 = a27;\nimport a27 = a28;\nimport a28 = a29;\nimport a29 = a30;\nimport a30 = a31;\nimport a31 = a32;\nimport a32 = a33;\nimport a33 = a34;\nimport a34 = a35;\nimport a35 = a36;\nimport a36 = a37;\nimport a37 = a38;\nimport a38 = a39;\nimport a39 = a40;\nimport a40 = a41;\nimport a41 = a42;\nimport a42 = a43;\nimport a43 = a44;\nimport a44 = a45;\nimport a45 = a46;\nimport a46 = a47;\nimport a47 = a48;\nimport a48 = a49;\nimport a49 = a50;\nimport a50 = a51;\nimport a51 = a52;\nimport a52 = a53;\nimport a53 = a54;\nimport a54 = a55;\nimport a55 = a56;\nimport a56 = a57;\nimport a57 = a58;\nimport a58 = a59;\nimport a59 = a60;\nimport a60 = a61;\nimport a61 = a62;\nimport a62 = a63;\nimport a63 = a64;\nimport a64 = a65;\nimport a65 = a66;\nimport a66 = a67;\nimport a67 = a68;\nimport a68 = a69;\nimport a69 = a70;\nimport a70 = a71;\nimport a71 = a72;\nimport a72 = a73;\nimport a73 = a74;\nimport a74 = a75;\nimport a75 = a76;\nimport a76 = a77;\nimport a77 = a78;\nimport a78 = a79;\nimport a79 = a80;\nimport a80 = a81;\nimport a81 = a82;\nimport a82 = a83;\nimport a83 = a84;\nimport a84 = a85;\nimport a85 = a86;\nimport a86 = a87;\nimport a87 = a88;\nimport a88 = a89;\nimport a89 = a90;\nimport a90 = a91;\nimport a91 = a92;\nimport a92 = a93;\nimport a93 = a94;\nimport a94 = a95;\nimport a95 = a96;\nimport a96 = a97;\nimport a97 = a98;\nimport a98 = a99;\nimport a99 = a100;\nimport a100 = a101;\nimport a101 = a1;\na1.nope;\nexport {};\nconst sentinel: number = \"\";\n", - "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\"}, \"files\": [\"main.ts\"]}" + "a.ts": "type S = [Extract, Extract];\ndeclare const g3: { readonly 7: 1; readonly \"8\": 1; 9: 1; 10: 1 };\nconst { 9: _c, ...r3 } = g3;\nconst g1 = { get 7() { return 1 }, set 8(v: number) {}, 9: 1, 10: 1 };\nconst { 9: _a, ...r1 } = g1;\nclass G2 { readonly 7 = 1; 9 = 1; 10 = 1 }\nconst { 9: _b, ...r2 } = new G2();\nconst t1: S = [\"?\", -99], t2: S = [\"?\", -99], t3: S = [\"?\", -99];\ntype M = { [K in keyof typeof r3]: K }; const m: M = 0;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "76-R05a": { + "92-R19c": { "files": { - "a.ts": "interface A { a: number }\ninterface B { b: number }\ninterface X5 extends A, B { [k: string]: X5[\"a\"] }\ndeclare const x5: X5;\nconst y5: number = x5.zzz;\nfunction f5(x: X5) { const r: number = x.zzz; }\ninterface Y5 extends X5 { more: 1 }\ndeclare const yy5: Y5;\nconst z5: number = yy5.zzz;\n// in tsc only the instantiation that the index signature names loses it\ninterface X8 extends A, B { [k: string]: X8[\"a\"] }\ndeclare const x8: X8;\nconst y8: number = x8.zzz;\ndeclare const x8n: X8;\nconst y8n: number = x8n.zzz;\n// an interface with `this`: the type itself loses it, an interface derived from it does not\ninterface X9 extends A, B { self: this; [k: string]: X9[\"a\"] | this }\ndeclare const x9: X9;\nconst y9: number | X9 = x9.zzz;\ninterface Y9 extends X9 { more: 1 }\ndeclare const yy9: Y9;\nconst z9: number | Y9 = yy9.zzz;\n// one base: the two agree\ninterface X7 extends A { [k: string]: X7[\"a\"] }\ndeclare const x7: X7;\nconst y7: number = x7.zzz;\nconst sentinel: number = \"\";\n", + "a.ts": "import * as m1 from \"./m1\";\ntype S = [Extract, Extract];\nconst t1: S = [\"?\", -99];\ntype M = { [K in keyof typeof m1]: K }; const m: M = 0;\nconst sentinel: number = \"\";\n", + "m1.ts": "const x = 1; export { x as \"0\", x as \"1.5\", x as \"a b\", x as y };\nexport * as \"2\" from \"./m2\";\n", + "m2.ts": "export const z = 1;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"module\":\"preserve\",\"moduleResolution\":\"bundler\" } }\n" + } + }, + "92-R19d": { + "files": { + "a.ts": "import * as j1 from \"./j1\";\nimport { K, o as jo } from \"./j3\";\ntype S = [Extract, Extract];\nconst t1: S = [\"?\", -99], t2: S = [\"?\", -99], t3: S = [\"?\", -99], t4: S = [\"?\", -99];\nconst sentinel: number = \"\";\n", + "j1.js": "exports[0] = 1; exports[\"1\"] = 2; exports.a = 3;\n", + "j3.js": "export class K { constructor() { this[0] = 1; this[\"1\"] = 2; this.a = 3; } }\nK[5] = 1; K[\"6\"] = 2;\nexport const o = {}; o[0] = 1; o[\"1\"] = 2; o.a = 3;\nObject.defineProperty(o, \"3\", { value: 1 }); Object.defineProperty(o, 4, { value: 1 });\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"],\"module\":\"preserve\",\"moduleResolution\":\"bundler\",\"allowJs\":true,\"checkJs\":true } }\n" + } + }, + "93-R01a": { + "files": { + "a.ts": "type M = { [K in \"a\" | \"b\" as A]: N[\"a\"] };\ntype A = M[\"a\"] & string;\ntype N = { [P in \"a\" | \"b\"]: M[\"b\"] };\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "77-R13a": { + "93-R01b": { "files": { - "a.js": "/** @param {any} a @param {number} extra */\nfunction t(a) { const x = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1; return arguments; }\n/** @type {number} */\nconst sentinel = \"\";\n", - "bun.stderr.txt": "error: ran out of stack in a.js. This is a bug in Bun: errors in this file may be missing.\nCould not finish checking 1 file, checked 58 files [10.60ms]\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "type M = { [K in \"a\" | \"b\" as Exclude]: N[\"a\"] };\ninterface N { a: M[\"b\"] }\nconst o = f().a;\ndeclare function f(): M;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "77-R13b": { + "93-R01c": { "files": { - "a.ts": "function t() { if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else if (1) {} else {} }\nconst sentinel: number = \"\";\n", - "bun.stderr.txt": "\nthread '' (140071976) has overflowed its stack\nfatal runtime error: stack overflow, aborting\n", + "a.ts": "type M = { [K in \"a\" | \"b\" as A]: N[\"a\"] };\ntype A = M[\"a\"] & string;\ninterface N { a: M[\"b\"] }\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" - }, - "deep": true + } }, - "79-R11": { + "93-R01d": { "files": { - "j.js": "class B { constructor() { this.x = new B().x; } m() { return this.x; } }\nclass D { constructor() { this.x = mk().x; } m() { return this.x; } } /** @returns {D} */ function mk() { return new D(); }\nclass E { constructor() { const t = mk2().x; this.x = t; } m() { return this.x; } } /** @returns {E} */ function mk2() { return new E(); }\nclass K { constructor() { this.x = new K; this.y = new K().x.y; } m() { return [this.x, this.y]; } }\nclass O { constructor(/** @type {O} */ o) { this.x = o.x; } m() { return this.x; } }\n/** @type {number} */ const sentinel = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"allowJs\": true, \"checkJs\": true } }\n" + "a.ts": "type M = { [K in keyof N as A[\"a\"] & string]: M[\"a\"] };\ntype A = { a: N[\"a\"]; b: 1 };\ntype N = { [P in \"a\" | \"b\"]: M[\"b\"] };\nlet m: M = 1;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "81-R02": { + "93-R03a": { "files": { - "a.ts": "function a1(x: T) { return x!.toUpperCase(); }\nfunction a2(x: T) { return x!.toFixed(); }\nfunction a3(o: { p: T }) { return o.p!.length; }\nfunction a4(f: () => NonNullable) { return f().length; }\nclass A5 { p!: T; m() { return this.p!.length; } }\nfunction a6(x: T) { x!.length = 1; }\n// the two agree: a constraint that is still a union or an object type after `& {}`, a reference in a constraint position\nfunction b1(x: T) { return x!.toString(); }\nfunction b2(x: T) { return x!.a; }\nfunction b3(x: NonNullable) { return x.length; }\nfunction b4(x: T) { return x![0]; }\nconst sentinel: number = \"\";\n", + "a.ts": "type X={x:1};type Y={y:1};type B={b:1};type C={c:1};type D={d:1};\ntype BCD = B & C & D;\ntype T1 = BCD & (X|Y);\ndeclare let v3: B & C & D & (X|Y);\nconst e3: number = v3;\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "81-R16": { + "93-R03b": { "files": { - "a.ts": "declare function run(f: () => T): T;\nfunction k6(ns: string[]) {\n let last: string | null = null;\n for (const n of ns) {\n if (n === last) continue;\n last = run(() => n);\n }\n}\nfunction k1(n: number, more: () => boolean) {\n let acc: number | null = null;\n while (more()) {\n if (n === acc) break;\n acc = [1].map(() => n)[0];\n }\n}\nasync function k21(y: \"a\" | \"b\", more: () => boolean) {\n let x: \"a\" | \"b\" = \"a\";\n while (more()) {\n if (y === x) { }\n x = await Promise.resolve().then(() => y);\n }\n}\n// the two agree: no initializer, a declared type that is no union, an annotated callback\nfunction a1(ns: string[]) { let last: string | undefined; for (const n of ns) { if (n === last) continue; last = run(() => n); } }\nfunction a2(ns: string[]) { let last = \"\"; for (const n of ns) { if (n === last) continue; last = run(() => n); } }\nfunction a3(ns: string[]) { let last: string | null = null; for (const n of ns) { if (n === last) continue; last = run((): string => n); } }\nconst sentinel: number = \"\";\n", + "a.ts": "type X={x:1};type Y={y:1};type B={b:1};type C={c:1};type D={d:1};\ntype BCD = B & C & D;\ntype T2 = B & C & D & (X|Y);\ndeclare let v4: BCD & (X|Y);\nconst e4: number = v4;\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "82-R17": { + "93-R04a": { "files": { - "a.ts": "export * from \"x\"\n\\u0077ith (a) {}\n", + "a.ts": "const a = { m() { return this.z; }, f() { return this.z; }, g() { return (1 + {}); } };\nconst b = { m() { return this.z; }, f() { return this.z; }, g: () => { return ([2 + {}]); } };\nconst c = { m() { return this.z; }, f() { return this.z; }, get g() { return (3 + {}, 1); } };\nconst d = { m() { return this.z; }, f() { return this.z; }, g: function () { return ((4 + {}) as any); } };\n// without the parentheses both tools lose the error\nconst e = { m() { return this.z; }, f() { return this.z; }, g() { return 5 + {}; } };\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "82-R17b": { + "93-R04b": { "files": { - "a.ts": "type T = A extends infer U \\u0065xtends B ? C : D;\n", + "a.ts": "declare function abs(n: number): number; declare let u: (() => number) | undefined;\nconst a = { m() { return this.z; }, f() { return this.z; }, g() { const q = (1, 2); return q; } };\nconst b = { m() { return this.z; }, f() { return this.z; }, g() { return abs(1) instanceof Object; } };\nconst c = { m() { return this.z; }, f() { return this.z; }, g() { return u(); } };\nconst d = { m() { return this.z; }, f() { return this.z; }, g() { return \"\" satisfies number; } };\nconst e = { m() { return this.z; }, f() { return this.z; }, g() { return { ...1 }; } };\nconst h = { m() { return this.z; }, f() { return this.z; }, g() { return new (class { private constructor() {} })(); } };\nconst i = { m() { return this.z; }, f() { return this.z; }, g() { return g2 ? 1 : 2; function g2() {} } };\nconst j = { m() { return this.z; }, f() { return this.z; }, g() { return /(/; } };\nconst k = { m() { return this.z; }, f() { return this.z; }, g() { return later; let later = 1; } };\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "82-R17c": { + "93-R04c": { "files": { - "a.ts": "\\u0065lse;\n", + "a.ts": "declare function id(x: T): T; declare function abs(n: number): number;\nconst a = { m() { return this.z; }, f() { return this.z; }, g: id(() => ({}).nope) };\nconst b = { m() { return this.z; }, f() { return this.z; }, g: id(() => nope) };\nconst c = { m() { return this.z; }, f() { return this.z; }, g: id(() => abs(\"\")) };\nconst d = { m() { return this.z; }, f() { return this.z; }, g: id(function () { return abs(\"\"); }) };\nconst e = { m() { return this.z; }, f() { return this.z; }, g: id({ h() { return abs(\"\"); } }) };\n// not an argument of a generic call: both tools lose the error\nconst h = { m() { return this.z; }, f() { return this.z; }, g: [() => abs(\"\")] };\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "82-R17d": { + "93-R05a": { "files": { - "a.ts": "switch (a) { case 1: else {} }\n", + "a.ts": "interface A1 { a: 1 }\nfunction f() {\n let p: U & A1 = null!;\n type T = U & {} & A1;\n const n: never = null! as T | (U & string) | (U & object);\n}\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "82-R17e": { + "93-R05b": { "files": { - "a.ts": "f(\\u0065lse);\n", + "a.ts": "interface A1 { a: 1 }\nfunction f() {\n type T = U & {} & A1;\n const n: never = null! as T | (U & string) | (U & object);\n const n2: never = null! as (U & A1) | (U & string) | (U & object);\n}\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "85-R03a": { + "93-R05c": { "files": { - "a1.js": "class C { p = [this.p, module]; }\nmodule.exports = C;\n", - "a2.js": "class C { static p = [C.p, exports]; }\nexports.C = C;\n", - "a3.js": "function f() {}\nf.p = [f.p, module];\nmodule.exports = f;\n", - "a4.js": "exports.a = [exports.a, module];\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n", - "zz.ts": "export {};\nconst sentinel: number = \"\";\n" + "a.ts": "interface A1 { a: 1 }\nfunction f() {\n type T1 = U & {} & A1;\n type T2 = U & A1;\n const n: never = null! as T1 | (U & string) | (U & object);\n const n2: never = null! as T2 | (U & string) | (U & object);\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "85-R03b": { + "93-R06b": { "files": { - "f.js": "var v = mk().x;\nfunction mk() { return new C(); }\nclass C { get x() { return [module, this.x]; } }\nv.nope;\nmodule.exports = C;\n/** @type {number} */\nconst sentinel = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": false, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "interface Base { base: T }\ninterface A extends Base { x: number }\ninterface C { x: number }\ndeclare let c: C; declare let a: A;\nconst arr = [a, c];\nconst arr2 = [a, c];\nconst n2: number = arr2;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "85-R03f": { + "93-R06c": { "files": { - "a.js": "var p = r;\nvar r = [r, require(\"./b\").y];\nexports.k = 1;\n/** @type {never} */ var tp = p;\n/** @type {number} */\nconst sentinel = \"\";\n", - "b.js": "exports.y = exports.z;\nexports.z = 1;\nvar p = r;\nvar r = [r, exports];\n/** @type {never} */ var tp = p;\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "type M = { [K in \"x\" | \"p\"]: K extends \"p\" ? typeof arr : number };\ninterface C { x: number; p: any }\ndeclare let m: M; declare let c: C;\nconst arr = [m, c];\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "85-R03g": { + "93-R11a": { "files": { - "a.js": "var p = r;\nvar r = [r, exports];\nexports.y = exports.z;\nexports.z = 1;\n/** @type {never} */ var tp = p;\n", - "b.js": "var q = s;\nvar s = [s, require(\"./a\").y, exports];\nexports.k = 1;\n/** @type {never} */ var tq = q;\n/** @type {number} */\nconst sentinel = \"\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"allowJs\": true, \"checkJs\": true, \"module\": \"commonjs\", \"types\": [], \"lib\": [\"es2022\"] } }\n" + "a.ts": "declare function id(u: U): U;\nclass C { w = ({ m() { return 1; }, id }).id<5>; }\nlet w: C[\"w\"] | C[\"w\"] = 1;\nfunction g(a = ({ m() { return 1; }, id }).id<6>) { return a; }\nlet a: ReturnType> | ReturnType> = 1;\nconst h = () => ({ m() { return 1; }, id }).id<7>;\nlet b: ReturnType> | ReturnType> = 1;\n// with a return type annotation the method does not count: one type in both tools\nclass D { w = ({ m(): number { return 1; }, id }).id<8>; }\nlet d: D[\"w\"] | D[\"w\"] = 1;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "87-R01e": { + "93-R11b": { "files": { - "a.ts": "type D = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';\ntype Mk = K extends any ? { a: K } : never;\ntype S = Mk<`s${D}${D}${D}`>;\ntype T = Mk<`t${D}${D}${D}` | `u${D}${D}${D}` | `v${D}${D}`> | { a: string };\ndeclare let s: S; declare let t: T; declare const c: boolean;\nclass G { v!: X }\nclass H extends G {}\nconst sentinel: number = \"\";\n", + "a.ts": "declare class D { n(u: U, t: T): T }\nconst mk = (d: D) => d.n<2>;\nmk(null! as D)(2, \"x\");\nconst r: string = mk(null! as D)(2, null!);\nclass C {\n n(u: U, t: T) { return t; }\n q = this.n<2>;\n}\nnew C().q(2, \"x\");\nfunction dflt(d: D, f = d.n<2>) { return f; }\ndflt(null! as D)(2, \"x\");\n// with a block on the way to the type parameter both tools instantiate\nfunction blk(d: D) { return d.n<2>; }\nblk(null! as D)(2, \"x\");\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, - "90-R06": { + "93-R11c": { "files": { - "a.ts": "import { which } from \"cond9000\"; const x: 0 = which;\nconst sentinel: number = \"\";\n", - "node_modules/cond9000/index.d.ts": "export declare const which: \"index\";\n", - "node_modules/cond9000/package.json": "{\"types\":\"u.d.ts\",\"exports\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":{\"types\":\"./t.d.ts\"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}", - "node_modules/cond9000/t.d.ts": "export declare const which: \"t\";\n", - "node_modules/cond9000/u.d.ts": "export declare const which: \"u\";\n", - "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"esnext\", \"moduleResolution\": \"bundler\" }, \"files\": [\"a.ts\"] }\n" - }, - "deep": true + "a.ts": "class C {\n m(u: U) { return u; }\n static sm(u: U) { return u; }\n a = ((u: U) => u)<1>;\n b = (function (u: U) { return u; })<2>;\n c = ({ m(u: U): U { return u; } }).m<3>;\n d = this.m<4>;\n e = C.sm<5>;\n}\nlet a: C[\"a\"] | C[\"a\"] = 1; let b: C[\"b\"] | C[\"b\"] = 1; let c: C[\"c\"] | C[\"c\"] = 1;\nlet d: C[\"d\"] | C[\"d\"] = 1; let e: C[\"e\"] | C[\"e\"] = 1;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } }, - "91-R05a": { + "93-R17a": { "files": { - "a.ts": "type as = number;\ntype satisfies = T;\nnamespace satisfies { export const y = 1; }\nnamespace N { interface as { a: number } }\nfunction f() { type as = 1; let x: as = 1; return x; }\nconst sentinel: number = \"\";\n", + "a.ts": "import * as r from \"./r\"; export const v = r.w;\n", + "r.ts": "import { v } from \"./a\"; export { v as w };\n", + "tsconfig.json": "{\"compilerOptions\": {\"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"]}}\n", + "zz_sentinel.ts": "const sentinel: number = \"\";\nexport {};\n" + } + }, + "93-R18a": { + "files": { + "a.ts": "interface Bad { then(): void }\ndeclare const p: Promise; declare const u: string | Bad;\nasync function f() { await p; await u; }\ninterface Bad2 { then(): void; x: 1 }\ndeclare const p2: Promise; declare const u2: string | Bad2;\nasync function g() { await u2; await p2; }\ntype S = string | Promise;\ndeclare const s: S; declare const ps: Promise;\nasync function h() { await ps; await s; }\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "93-R18b": { + "files": { + "a.ts": "declare function gen(a: T[]): T;\ndeclare function over(a: number[], b: string): 1; declare function over(a: number[], b: number): 2;\ndeclare function wrap(a: T): T;\ndeclare function call(a: () => T): T;\ndeclare const b1: { [Symbol.iterator](): { next(): IteratorResult; return: number } };\ngen([...b1]);\ndeclare const b2: { [Symbol.iterator](): { next(): IteratorResult; return: string } };\nover([...b2], 1);\ndeclare const b3: { [Symbol.iterator](): { next(): IteratorResult; return: boolean } };\n[1].concat([...b3]);\ndeclare const b4: { [Symbol.iterator](): { next(): { done: boolean } } };\ngen([...b4]);\ndeclare const b5: { [Symbol.iterator](): { next(): IteratorResult; throw: number } };\nwrap({ a: [...b5] });\ndeclare const b6: { [Symbol.iterator](): { next(): IteratorResult; throw: string } };\ncall(() => [...b6]);\n// one signature that is not generic: both tools report\ndeclare function one(a: number[]): void;\ndeclare const b7: { [Symbol.iterator](): { next(): IteratorResult; throw: boolean } };\none([...b7]);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "93-R19a": { + "files": { + "a.ts": "declare const b1: { [Symbol.iterator](): { next(): IteratorResult; return: number } };\nconst r1 = f1();\nfunction f1() { let a: number | string; [a] = b1; return a; }\ndeclare const b2: { [Symbol.iterator](): { next(): IteratorResult; return: string } };\nconst r2 = f2();\nfunction f2() { let a: number | string, b: number[] | string; [a, ...b] = b2; return b; }\ndeclare const b3: { [Symbol.iterator](): { next(): IteratorResult; return: boolean } };\nconst r3 = f3();\nfunction f3() { let a: number | string; ({ p: [a] } = { p: b3 }); return a; }\n// the function first, the call after: both tools report\ndeclare const b4: { [Symbol.iterator](): { next(): IteratorResult; throw: number } };\nfunction f4() { let a: number | string; [a] = b4; return a; }\nconst r4 = f4();\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "94-R01a": { + "files": { + "a.ts": "import * as ns from \"./b\";\nexport function fa() { return ns.foo; }\nns.nope;\nconst sentinel: number = \"\";\n", + "b.ts": "import A = require(\"./a\");\nconst o = { foo: 1, get g() { return A.fa(); }, default: 1 };\nexport = o;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" } }\n" + } + }, + "94-R01c": { + "files": { + "a.ts": "import * as ns from \"./b\";\nimport * as ns2 from \"./b\";\nexport const a2 = ns.foo2;\nexport const a = ns2.foo;\nconst sentinel: number = \"\";\n", + "b.ts": "import { a, a2 } from \"./a\";\nconst o = { foo2: a2, foo: a };\nexport = o;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" }, \"files\": [\"b.ts\"] }\n" + } + }, + "94-R04a": { + "files": { + "a.ts": "import d from \"./b\";\nexport default d;\nconst n: number = d;\nd.nope;\nconst sentinel: number = \"\";\n", + "b.ts": "import a = require(\"./a\");\nexport = a;\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"module\": \"commonjs\" } }\n", + "u.ts": "import d from \"./a\";\nimport b from \"./b\";\nconst n: number = d;\nconst m: number = b;\n" + } + }, + "94-R07": { + "files": { + "a.ts": "export {};\ndeclare global {\n interface String { me(): this; [Symbol.iterator](): IterableIterator; }\n interface Number { me(): this }\n}\nfunction f(d: D, n: N) {\n const a: D = d.me();\n const b: string = d.me();\n const c: N = n.me();\n const e: number = n.me();\n for (const z of d) { const g: D = z; }\n const [h]: D[] = [...d];\n}\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, @@ -11744,6 +15123,13 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noErrorTruncation\": true } }\n" } }, + "95-Z4": { + "files": { + "S136.txt": "a.ts(6,7): error TS2322: Type 'null' is not assignable to type '[[unknown]]'.\na.ts(7,7): error TS2322: Type 'null' is not assignable to type '[[unknown]]'.\na.ts(8,7): error TS2322: Type 'null' is not assignable to type '[[unknown]]'.\na.ts(10,7): error TS2322: Type 'null' is not assignable to type '[[unknown]]'.\na.ts(11,7): error TS2322: Type 'null' is not assignable to type '[[unknown]]'.\na.ts(12,7): error TS2322: Type 'null' is not assignable to type '[[unknown]]'.\na.ts(17,7): error TS2322: Type 'null' is not assignable to type '[[unknown]]'.\na.ts(18,7): error TS2322: Type 'null' is not assignable to type '[unknown]'.\na.ts(19,7): error TS2322: Type 'null' is not assignable to type '[unknown] | [[unknown]]'.\na.ts(24,7): error TS2322: Type 'null' is not assignable to type '[5 | 6 | [unknown]]'.\na.ts(25,7): error TS2322: Type 'null' is not assignable to type '6 | [unknown]'.\na.ts(26,7): error TS2322: Type 'null' is not assignable to type '6 | [unknown] | [5 | 6 | [unknown]]'.\na.ts(27,7): error TS2322: Type 'string' is not assignable to type 'number'.\n", + "a.ts": "// `getConditionalTypeInstantiation` calls `getConditionalType` for each member of the union it distributes over: that call reads\n// no entry of `root.instantiations` and stores none. It shows where the result depends on when it is computed: here the mapped type\n// has its members in place (empty) while they are resolved, so the inner `D` is `[unknown]` and the outer one `[[unknown]]`.\ntype S1 = { [k: string]: 1 }; type S2 = { [k: string]: 2 }; type S3 = { [k: string]: 3 };\ntype D = T extends object ? [{ [P in keyof T]: D }[keyof T]] : 2;\nconst d1: D = null; // the outer evaluations, not stored\nconst d2: D = null; // the entry of the inner one\nconst d3: D = null; // computed again\ntype E = T extends object ? [{ [P in keyof T]: E }[keyof T]] : 2;\nconst e1: E = null;\nconst e2: E = null;\nconst e3: E = null;\n// Through a tail call `F` is evaluated in the loop of `getConditionalType`: nothing is stored for it. A member is computed again.\ntype F = T extends object ? [{ [P in keyof T]: F1 | F2 }[keyof T]] : 2;\ntype F1 = T extends object ? F : 3;\ntype F2 = T extends object ? F : 4;\nconst f1: F = null;\nconst f2: F2 = null;\nconst f3: F2 = null;\n// Not a tail call: `H2` reads the entry that the inner `H` has stored. A member is computed again, with the entry of the outer one.\ntype H = T extends object ? [{ [P in keyof T]: H1 | H2 }[keyof T]] : 2;\ntype H1 = T extends object ? H | 5 : 3;\ntype H2 = T extends object ? H | 6 : 4;\nconst h1: H = null;\nconst h2: H2 = null;\nconst h3: H2 = null;\nconst sentinel: number = '';\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"noErrorTruncation\": true } }\n" + } + }, "96-ARKTYPE2": { "files": { "a.ts": "type In = t extends string ? string : never\n\n// arktype's `attest(actual).satisfies(def)`: an error in `actual` makes `expected` the error type\ntype overlaps = l & r extends never ? false : true\ntype Assertions = { satisfies: (def: overlaps> extends true ? unknown : \"no overlap\") => void }\ndeclare function attest(actual: expected): Assertions\ndeclare const n: never\nattest(n.foo).satisfies(1)\n\n// the same with a plain `any`\ninterface C {\n\tm(x: T & In): void\n\tp1(y: T & In, x: U): void\n\tp2(y: T & In, x: U): void\n}\ndeclare const c: C\nc.m(1)\nc.m(1)\nc.p1(2, 1)\nc.p1(2, 1)\n// nothing has asked for the type of `y` of `C.p2` before it is instantiated: 'never' in both\nc.p2(2, 1)\nclass K { m(x: T & In): void {} }\nnew K().m(1)\ndeclare function f(): (x: T & In) => void\nf()(1)\nconst sentinel: number = \"\";\n", @@ -11818,6 +15204,30 @@ "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } }, + "96-KY1": { + "files": { + "a.ts": "// ky: source/types/common.ts (`_?: never` became `_: never`), source/types/options.ts, source/core/Ky.ts(397,4)\ntype LiteralUnion = L | (B & { _: never });\ntype HttpMethod = LiteralUnion<\"get\" | \"post\", string>;\ntype KyOptions = { json?: unknown };\ninterface Options extends KyOptions {\n method?: LiteralUnion | undefined;\n}\ndeclare const s: string;\nexport const ky: Options = { method: s };\n\n// The mechanism: an alias applied to a union that already has everything the alias adds.\ntype Maybe = T | undefined;\ntype Handler = Maybe<() => void>;\nnamespace N {\n export type Local = Handler | undefined;\n}\ntype Wrap = { x: T };\ninterface G {\n t: T;\n a: Maybe;\n b: Maybe>;\n c: Maybe>>;\n d: Wrap>;\n e: N.Local;\n // Controls, the same in both tools.\n f: Maybe>;\n g: Maybe>;\n h: { x: Maybe };\n}\ndeclare const g: G;\nexport const a: 0 = g.a;\nexport const b: 0 = g.b;\nexport const c: 0 = g.c;\nexport const d: 0 = g.d;\nexport const e: 0 = g.e;\nexport const f: 0 = g.f;\nexport const g1: 0 = g.g;\nexport const h: 0 = g.h;\n\n// A class has a `this` type, so every member whose type node is not \"thisless\" is instantiated.\nclass C {\n a: readonly Maybe[] = [];\n b: [Maybe] = [undefined];\n c: Promise> | null = null;\n}\ndeclare const o: C;\no.a = 1;\no.b = 1;\no.c = 1;\n\n// The signature of a generic function, instantiated by a call.\ndeclare function ret(t: T): Maybe;\ndeclare function par(t: T, m: Maybe): void;\nexport const r: 0 = ret(1);\npar(1, 1);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "96-KYSELY1": { + "files": { + "a.ts": "declare class K {\n d: D\n p(): K\n e(): K<[D, T]>\n x(): string\n}\ndeclare class R extends K {\n p(): R\n e(): R<[D, T]>\n x(): unknown\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "96-KYSELY2": { + "files": { + "a.ts": "declare class K { d: D; e(): K<[D]>; x(): string }\ndeclare class S { d: D; e(): S<[D]>; x(): D extends [[any]] ? number : string }\ndeclare class R extends K {}\ndeclare function mk(): S\nconst k: K = mk()\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "96-OPENAI1": { + "files": { + "a.ts": "declare const c: boolean;\n// The shape of openai-node, src/_vendor/zod-to-json-schema: `{} & Meta` is `Meta`, a supertype of the other members.\ntype Meta = { title?: string };\ntype Schema = ({ type: \"string\" } | { type: \"number\" } | {}) & Meta;\ntype MapType = { maxItems: 125; items: [Schema, Schema] };\ntype RecordType = { type: \"object\"; additionalProperties: Schema };\ndeclare function parseDef(): Schema | undefined;\nfunction parseMapDef(): MapType | RecordType {\n const keys = parseDef() || {};\n return { type: \"array\", maxItems: 125, items: [keys, keys] };\n}\n// Ordinary code: a named union with a member that is a supertype of all the others.\ninterface Animal { name: string }\ninterface Dog extends Animal { bark(): void }\ninterface Cat extends Animal { meow(): void }\ntype Pet = Animal | Dog;\ndeclare const a: Pet, b: Pet, u: Pet | undefined, dog: Dog, cat: Cat;\nconst x = c ? a : b;\nif (\"bark\" in x) x.bark();\nfor (const e of [a, b]) if (\"bark\" in e) e.bark();\nlet y = u ?? b;\ny = { name: \"\", bark() {} };\nconst t1: number = c ? a : b;\nconst t2: number = [a, b];\nconst t3: number = u || b;\nconst t4: number = u ?? b;\nconst t5: number = c ? a : dog;\nconst t6: number = c ? a : cat;\n// Named by an origin, without an alias.\ndeclare const o: ({ type: \"s\" } | { type: \"n\" } | {}) & Meta;\nconst t7: number = c ? o : o;\n// reduceVoidUndefined of removeRedundantLiteralTypes: one member is left, two are left.\ntype VU = void | undefined;\ntype VUS = void | undefined | string;\ndeclare const vu: VU, vus: VUS;\nconst t8: number = c ? vu : vu;\nconst t9: number = c ? vus : vus;\n// The two agree: two members are left, two named unions, a named union inside `Pet | undefined`.\ntype Three = Animal | Dog | string;\ntype Pet2 = Animal | Cat;\ndeclare const three: Three, p2: Pet2;\nconst s1: number = c ? three : three;\nconst s2: number = c ? a : p2;\nconst s3: number = c ? u : a;\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, "96-REACTHOOKFORM1": { "files": { "a.ts": "import type { Message, Rule } from './types';\ndeclare function get(rule: Rule | Message): void;\ndeclare const rule: Rule | undefined;\nget(rule);\nconst sentinel: number = \"\";\n", @@ -11877,5 +15287,56 @@ "b.ts": "// Neighbours: EVERY member propagates its flags in `checkObjectLiteral`, also one that leaves no property in the type.\nexport {};\ndeclare const key: string;\ndeclare const num: number;\ndeclare const sym: symbol;\ndeclare const obj: {};\ntype Fn = (value: string) => unknown;\ndeclare function f

>(p: P): P;\nf({ [num]: (value) => value.nope });\nf({ [sym]: (value) => value.nope });\nf({ [key](value) { return value.nope } });\nf({ ...{}, [key]: (value) => value.nope });\ndeclare function nested

}>(p: P): P;\nnested({ a: { [key]: (value) => value.nope } });\ndeclare function list

>(...p: P[]): P;\nlist({ [key]: (value) => value.nope });\n// What is inferred: nothing in the first pass, so `P` comes from the return type.\ndeclare function g

(p: P, q: (p: P) => void): P;\nconst r1: number = g({ [key]: (value: any) => true, b: () => 1 }, (p) => {});\nconst r2: number = g({ [key]: (value) => true }, (p) => {});\nconst r3: number = g({ a: (value) => true, a: 1 }, (p) => {});\nconst r4: number = g({ [obj]: (value) => true, b: 1 }, (p) => {});\nconst sentinel: number = \"\";\n", "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" } + }, + "97-J1": { + "files": { + "App.TSX": "export const e =

;\n", + "b.Tsx": "export const e =
;\n", + "c.tsx": "export const e =
;\n", + "s.ts": "export const sentinel: number = \"\";\n", + "tsconfig.json": "{\n \"compilerOptions\": {\n \"strict\": true,\n \"noEmit\": true,\n \"target\": \"esnext\",\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"lib\": [\n \"esnext\"\n ],\n \"types\": [],\n \"skipLibCheck\": true,\n \"jsx\": \"react-jsx\",\n \"allowJs\": true,\n \"checkJs\": true\n },\n \"files\": [\n \"App.TSX\",\n \"b.Tsx\",\n \"z.JSX\",\n \"c.tsx\",\n \"s.ts\"\n ]\n}", + "z.JSX": "export const e =
;\n" + } + }, + "97-M1": { + "files": { + "a.ts": "import { I } from \"./lib\";\nexport const v = 1 & I;\n", + "b.ts": "import { A } from \"./lib\";\nexport const v = A;\n", + "c.ts": "import { N } from \"./lib\";\nexport const v = N;\n", + "d.ts": "interface J { x: number }\nexport const v = J;\n", + "f.ts": "import type { K } from \"./lib\";\nexport const v = new K();\n", + "g.ts": "import { I } from \"./lib\";\nexport const v = I;\nexport const w: I = { x: 1 };\n", + "h.ts": "import { I, A } from \"./lib\";\nexport const v = I.x;\nexport const w = A();\n", + "j.ts": "import { I } from \"./lib\";\nexport const v = { I };\n", + "k.ts": "import { I } from \"./lib\";\nexport { I };\n", + "l.ts": "import { I } from \"./lib\";\nexport const v = ({}) instanceof I;\n", + "lib.ts": "export interface I { x: number }\nexport type A = { y: number };\nexport declare namespace N { interface T {} }\nexport class K {}\n", + "tsconfig.json": "{\n \"compilerOptions\": {\n \"strict\": true,\n \"noEmit\": true,\n \"target\": \"esnext\",\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"lib\": [\n \"esnext\"\n ],\n \"types\": [],\n \"skipLibCheck\": true,\n \"noUnusedLocals\": true\n }\n}", + "z.ts": "export const sentinel: number = \"\";\n" + } + }, + "97-M2": { + "files": { + "a.ts": "import { FieldPath, Values, get } from \"./lib\";\n// Used as it is written: the alias of the import.\nexport function f(b: FieldPath) {\n const n: number = b;\n}\n", + "b.ts": "import { FieldPath, Values, get } from \"./lib\";\n// Instantiated, by a mapper that does not map V: the alias of the conditional type itself.\nexport function f(bs: ReadonlyArray>) {\n bs.map(name => get({}, name));\n}\n", + "c.ts": "import { FieldPath, Values, get } from \"./lib\";\ndeclare function isString(v: unknown): v is string;\nexport function f() {\n return (names?: FieldPath | ReadonlyArray>) =>\n names === undefined ? 1 : isString(names) ? get({}, names) : names.map(name => get({}, name));\n}\n", + "f.ts": "import { FieldPath, Values, get } from \"./lib\";\nexport function f(names: FieldPath | ReadonlyArray>) {\n return typeof names === \"string\" ? 1 : names.map(name => get({}, name));\n}\n", + "g.ts": "import { FieldPath, Values, get } from \"./lib\";\nexport function f(names: FieldPath | ReadonlyArray>) {\n get({}, names);\n}\n", + "lib.ts": "type Inner = keyof T & string;\nexport type Values = Record;\nexport type Path = T extends any ? Inner : never;\nexport type FieldPath = Path;\nexport declare function get(o: unknown, p?: number | null): unknown;\n", + "tsconfig.json": "{\n \"compilerOptions\": {\n \"strict\": true,\n \"noEmit\": true,\n \"target\": \"esnext\",\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"lib\": [\n \"esnext\"\n ],\n \"types\": [],\n \"skipLibCheck\": true\n }\n}", + "z.ts": "export const sentinel: number = \"\";\n" + } + }, + "98-F1": { + "files": { + "a.ts": "declare const k: unique symbol;\nconst c = \"x\";\nexport class C {\n [\"\\0\\0\\u007f\\u007f\\u007f\\u007f\"]: number;\n [\"\\0\\u0001\\u007f\\u007f\\u007f\\u007f\"]: number;\n [c]: number;\n [k]: number;\n constructor() {\n for (;;) {\n if (Math.random()) break;\n }\n this[c] = 1;\n }\n}\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"] } }\n" + } + }, + "98-J1": { + "files": { + "a.tsx": "declare namespace JSX { interface IntrinsicElements { [name: string]: any } interface Element {} }\ndeclare const isLogin: boolean;\ndeclare const DEFAULT_NULL_VALUE: string;\ndeclare const HoverCardText: (p: { label: any }) => null;\n// `(DEFAULT_NULL_VALUE): (\n {isLogin ? (DEFAULT_NULL_VALUE) : ({('', { s1: (1, { precision: '' }), s2: (2, { precision: '' }) })}
}>)}\n
\n);\nconst sentinel: number = \"\";\n", + "tsconfig.json": "{ \"compilerOptions\": { \"strict\": true, \"noEmit\": true, \"types\": [], \"lib\": [\"es2022\"], \"jsx\": \"preserve\" } }\n" + } } } diff --git a/test/cli/check/differential.ts b/test/cli/check/differential.ts index 5c80b4b1d3ce..c6f8619ae280 100644 --- a/test/cli/check/differential.ts +++ b/test/cli/check/differential.ts @@ -1,5 +1,6 @@ import { expect, test } from "bun:test"; import { bunEnv, bunExe, isASAN, isDebug, isWindows, tempDir } from "harness"; +import { mkdirSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; // `bun check` follows TypeScript 7, which is a native program next to its `lib.*.d.ts`: `typescript7` in @@ -41,7 +42,7 @@ export async function inTurns(items: T[], run: (item: T) => Promise) { for (let at = 0; at < items.length; at += 6) await Promise.all(items.slice(at, at + 6).map(run)); } -/** `deep`: nested too deeply for the stack of a build that is not optimised. */ +/** `deep`: nested too deeply for the stack of a build that is not optimised, or too slow in one. */ type Case = { files: Record; build?: true; deep?: true }; /** @@ -55,17 +56,28 @@ export function programsThatOnceDiffered(part: number, parts: number) { `programs about which the two once differed, ${part * tests + nth + 1} of ${parts * tests}`, async () => { const all: Record = await Bun.file(join(import.meta.dir, "differential-cases.json")).json(); + using dir = tempDir("bun-check-differential", {}); + const root = String(dir); const cases = Object.entries(all) .filter(([, it]) => !(it.deep && (isDebug || isASAN))) // A debug build checks a sample. It is always the same sample. .filter((_, index) => index % (isDebug || isASAN ? 40 : 1) === 0) .filter((_, index) => index % (parts * tests) === part * tests + nth) - // Windows cannot create a directory named `c:`. - .filter(([, it]) => !isWindows || !Object.keys(it.files).some(path => path.includes(":"))); - const files: Record = {}; - for (const [name, it] of cases) for (const path in it.files) files[`${name}/${path}`] = it.files[path]; - using dir = tempDir("bun-check-differential", files); - const root = String(dir); + // Windows cannot create a directory named `c:` or `w*d`. + .filter(([, it]) => !isWindows || !Object.keys(it.files).some(path => /[:*?"<>|]/.test(path))) + .filter(([name, it]) => { + try { + for (const path in it.files) { + mkdirSync(dirname(join(root, name, path)), { recursive: true }); + writeFileSync(join(root, name, path), it.files[path]); + } + return true; + } catch (error) { + // APFS refuses a character that is newer than the Unicode tables of the system. + if ((error as NodeJS.ErrnoException).code === "EILSEQ") return false; + throw error; + } + }); const different: Record = {}; await inTurns(cases, async ([name, it]) => { const cwd = join(root, name);