From c7c951153140dd1c9321d6668b88e3ef253d05bf Mon Sep 17 00:00:00 2001 From: Nick Nassiri Date: Wed, 8 Jul 2026 23:49:57 -0700 Subject: [PATCH 01/11] =?UTF-8?q?feat(types):=20#99=20seam=20=E2=80=94=20r?= =?UTF-8?q?esolve=20ambient=20lib=20types=20(Symbol,=20SymbolConstructor)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First increment of #99 (lib.d.ts modeling), seam-first: a single TryResolveLibType switch, consulted by both ResolveTypeNameCore (for the type) and ReportUnknownTypeName (so the name isn't flagged TS2304), resolves TYPE-position lib names SharpTS doesn't yet parse from the vendored .d.ts files. Checked AFTER user declarations so a user interface of the same name wins. A later increment backs this switch with a real lib.d.ts loader. Covers the Symbol family: SymbolConstructor -> the existing WellKnownSymbolTypes shape; Symbol -> a new member-less wrapper interface (a symbol value is assignable to it, but it is not assignable back to the symbol primitive). Flips symbolProperty55, symbolType15. --- TypeSystem/TypeChecker.Statements.cs | 2 ++ TypeSystem/TypeChecker.TypeParsing.cs | 22 ++++++++++++++++++++++ TypeSystem/WellKnownSymbolTypes.cs | 13 +++++++++++++ 3 files changed, 37 insertions(+) diff --git a/TypeSystem/TypeChecker.Statements.cs b/TypeSystem/TypeChecker.Statements.cs index 584a9e9f..dbcbcb62 100644 --- a/TypeSystem/TypeChecker.Statements.cs +++ b/TypeSystem/TypeChecker.Statements.cs @@ -297,6 +297,8 @@ private void ReportUnknownTypeName(string? annotation, TypeNode? annotationNode, if (_environment.GetTypeAlias(name) is not null) return; if (_environment.GetGenericTypeAlias(name) is not null) return; if (_openTypeVariablesInScope?.Contains(name) == true) return; + // #99 lib-type seam: an ambient lib.d.ts type name (e.g. Symbol/SymbolConstructor) is known. + if (TryResolveLibType(name) is not null) return; throw new TypeCheckException($" Cannot find name '{name}'.", line, tsCode: "TS2304"); } diff --git a/TypeSystem/TypeChecker.TypeParsing.cs b/TypeSystem/TypeChecker.TypeParsing.cs index 09b176b5..98ff9e89 100644 --- a/TypeSystem/TypeChecker.TypeParsing.cs +++ b/TypeSystem/TypeChecker.TypeParsing.cs @@ -232,9 +232,31 @@ private TypeInfo ResolveTypeNameCore(string typeName) return enumType; } + // #99 lib-type seam: ambient lib.d.ts TYPE-position names SharpTS doesn't load from the + // .d.ts files yet (checked AFTER user declarations above, so a user interface of the same + // name wins). A later increment backs this with a real lib.d.ts loader. + if (TryResolveLibType(typeName) is { } libType) + { + return libType; + } + return new TypeInfo.Any(); } + /// + /// The #99 lib-type seam: resolves the ambient TYPE-position names that lib.d.ts declares but + /// SharpTS doesn't yet parse from the vendored .d.ts files, to their modeled . + /// Consulted by both (for the type) and + /// ReportUnknownTypeName (so these names aren't flagged TS2304). Increment 1 covers the + /// Symbol family; a later increment replaces this switch with content loaded from lib.d.ts. + /// + private static TypeInfo? TryResolveLibType(string name) => name switch + { + "SymbolConstructor" => WellKnownSymbolTypes.SymbolConstructor, + "Symbol" => WellKnownSymbolTypes.SymbolWrapper, + _ => null + }; + /// /// Simplifies an intersection type according to TypeScript semantics: /// - Conflicting primitives (string & number) = never diff --git a/TypeSystem/WellKnownSymbolTypes.cs b/TypeSystem/WellKnownSymbolTypes.cs index ef7333fd..7a700d60 100644 --- a/TypeSystem/WellKnownSymbolTypes.cs +++ b/TypeSystem/WellKnownSymbolTypes.cs @@ -74,6 +74,19 @@ public static class WellKnownSymbolTypes /// CheckGet) before generic member lookup ever consults this type, so adding it here doesn't /// change those paths — only genuine "use Symbol as a plain value" sites. /// + /// + /// The global `Symbol` WRAPPER object type (lib's `interface Symbol`), as it appears in TYPE + /// position (`var s: Symbol`). Distinct from the `symbol` primitive: a `symbol` value IS + /// assignable to this wrapper (an object-like target — the wrapper is modeled member-less so a + /// symbol satisfies it without SharpTS having to model symbol's apparent toString/valueOf), but + /// the wrapper is NOT assignable back to the `symbol` primitive (TS2322 "'symbol' is a primitive, + /// but 'Symbol' is a wrapper object"). + /// + public static readonly TypeInfo.Interface SymbolWrapper = new( + "Symbol", + FrozenDictionary.Empty, + FrozenSet.Empty); + public static readonly TypeInfo.Interface SymbolConstructor = new( "SymbolConstructor", new Dictionary From b189af24993d35c4c6512437489f4ca33b9a5b1c Mon Sep 17 00:00:00 2001 From: Nick Nassiri Date: Wed, 8 Jul 2026 23:49:57 -0700 Subject: [PATCH 02/11] =?UTF-8?q?test(conformance):=20update=20baseline=20?= =?UTF-8?q?=E2=80=94=20symbolProperty55=20+=20symbolType15=20now=20pass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SharpTS.TypeScriptConformance/baselines/interpreted.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharpTS.TypeScriptConformance/baselines/interpreted.txt b/SharpTS.TypeScriptConformance/baselines/interpreted.txt index a9f1658e..f5cd1bf7 100644 --- a/SharpTS.TypeScriptConformance/baselines/interpreted.txt +++ b/SharpTS.TypeScriptConformance/baselines/interpreted.txt @@ -132,7 +132,7 @@ tests/cases/conformance/es6/Symbols/symbolProperty51.ts Pass tests/cases/conformance/es6/Symbols/symbolProperty52.ts Pass tests/cases/conformance/es6/Symbols/symbolProperty53.ts Pass tests/cases/conformance/es6/Symbols/symbolProperty54.ts Pass -tests/cases/conformance/es6/Symbols/symbolProperty55.ts Fail +tests/cases/conformance/es6/Symbols/symbolProperty55.ts Pass tests/cases/conformance/es6/Symbols/symbolProperty56.ts Pass tests/cases/conformance/es6/Symbols/symbolProperty57.ts Pass tests/cases/conformance/es6/Symbols/symbolProperty58.ts Pass @@ -149,7 +149,7 @@ tests/cases/conformance/es6/Symbols/symbolType11.ts Pass tests/cases/conformance/es6/Symbols/symbolType12.ts Pass tests/cases/conformance/es6/Symbols/symbolType13.ts Pass tests/cases/conformance/es6/Symbols/symbolType14.ts Pass -tests/cases/conformance/es6/Symbols/symbolType15.ts Fail +tests/cases/conformance/es6/Symbols/symbolType15.ts Pass tests/cases/conformance/es6/Symbols/symbolType16.ts Pass tests/cases/conformance/es6/Symbols/symbolType17.ts Pass tests/cases/conformance/es6/Symbols/symbolType18.ts Pass From 3be1b33ef0850f7190f2090d1822843a0f08f99a Mon Sep 17 00:00:00 2001 From: Nick Nassiri Date: Thu, 9 Jul 2026 00:50:52 -0700 Subject: [PATCH 03/11] =?UTF-8?q?feat(types):=20#99=20incr=202a=20?= =?UTF-8?q?=E2=80=94=20lib.d.ts=20loader=20(parse=20embedded=20lib=20->=20?= =?UTF-8?q?TypeInfo)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The real-loader foundation for #99 increment 2. LibTypeLoader parses ambient lib declarations embedded as libdefs/*.d.ts resources (the vendored TypeScript lib is a dev-only submodule, so it must be embedded to work at runtime) and resolves them to modeled TypeInfo via a throwaway checker's new ExtractLibTypes (PreRegister into a fresh env, diagnostics suppressed, extracted by name). Built once, cached process-wide. TryResolveLibType now sources SymbolConstructor from the LOADED lib instead of a hand-modeled shape (Symbol stays hand-modeled — the wrapper needs a member-less shape a symbol can satisfy, which the loaded interface can't give until primitive apparent members are modeled). No baseline change (symbolProperty55/symbolType15 still pass); this is the pipeline that later increments fill from the real es5.d.ts + resolve the primitive-vs-interface tension to flip the remaining lib tests. Full xUnit 15452/0, conformance 252 Pass (0 regressions). --- SharpTS.csproj | 6 ++++ TypeSystem/LibTypeLoader.cs | 49 +++++++++++++++++++++++++++ TypeSystem/TypeChecker.TypeParsing.cs | 16 ++++++--- TypeSystem/TypeChecker.cs | 24 +++++++++++++ libdefs/lib.core.d.ts | 22 ++++++++++++ 5 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 TypeSystem/LibTypeLoader.cs create mode 100644 libdefs/lib.core.d.ts diff --git a/SharpTS.csproj b/SharpTS.csproj index 4f53df48..e708acf1 100644 --- a/SharpTS.csproj +++ b/SharpTS.csproj @@ -44,6 +44,12 @@ + + + + + +