diff --git a/internal/debug/debug.go b/internal/debug/debug.go index dba5b1d9802..47bced4d7f9 100644 --- a/internal/debug/debug.go +++ b/internal/debug/debug.go @@ -2,6 +2,8 @@ package debug import ( "fmt" + + "github.com/microsoft/typescript-go/internal/typeutil" ) func Fail(reason string) { @@ -14,7 +16,7 @@ func Fail(reason string) { panic(reason) } -func FailBadSyntaxKind(node interface{ KindString() string }, message ...any) { +func FailBadSyntaxKind(node interface{ KindString() string } /*ref:nonnil*/, message ...any) { var msg string if len(message) == 0 { msg = "Unexpected node." @@ -42,6 +44,25 @@ func AssertNever(member any, message ...any) { Fail(fmt.Sprintf("%s %s", msg, detail)) } +func AssertNeverR[T any](member typeutil.Never, message ...any) T { + var msg string + if len(message) == 0 { + msg = "Illegal value:" + } else { + msg = fmt.Sprint(message...) + } + var detail string + if m, ok := member.(interface{ KindString() string }); ok { + detail = m.KindString() + } else if m, ok := member.(fmt.Stringer); ok { + detail = m.String() + } else { + detail = fmt.Sprintf("%v", member) + } + Fail(fmt.Sprintf("%s %s", msg, detail)) + panic("unreachable") +} + func Assert(value bool, message ...any) { if value { return diff --git a/internal/glob/glob.go b/internal/glob/glob.go index 972c7a2b2f6..0fc7d3b19ca 100644 --- a/internal/glob/glob.go +++ b/internal/glob/glob.go @@ -9,6 +9,8 @@ import ( "fmt" "strings" "unicode/utf8" + + "github.com/microsoft/typescript-go/internal/typeutil" ) // A Glob is an LSP-compliant glob pattern, as defined by the spec: @@ -42,6 +44,10 @@ type Glob struct { elems []element // pattern elements } +var _ typeutil.UnusedAny = nil + +type DefGlob = *Glob /* ref: nonnil */ + // Parse builds a Glob for the given pattern, returning an error if the pattern // is invalid. func Parse(pattern string) (*Glob, error) { @@ -49,7 +55,7 @@ func Parse(pattern string) (*Glob, error) { return g, err } -func parse(pattern string, nested bool) (*Glob, string, error) { +func parse(pattern string, nested bool) (*Glob, string, error) /* ref: (DefGlob, string, nil) | (nil, string, typeutil.DefError) */ { g := new(Glob) for len(pattern) > 0 { switch pattern[0] { @@ -150,11 +156,11 @@ func readRangeRune(input string) (rune, int, error) { } var ( - errBadRange = errors.New("'[' patterns must be of the form [x-y]") - errInvalidUTF8 = errors.New("invalid UTF-8 encoding") + errBadRange typeutil.DefError = errors.New("'[' patterns must be of the form [x-y]") + errInvalidUTF8 typeutil.DefError = errors.New("invalid UTF-8 encoding") ) -func (g *Glob) parseLiteral(pattern string, nested bool) string { +func (g DefGlob) parseLiteral(pattern string, nested bool) string { var specialChars string if nested { specialChars = "*?{[/}," @@ -169,7 +175,7 @@ func (g *Glob) parseLiteral(pattern string, nested bool) string { return pattern[end:] } -func (g *Glob) String() string { +func (g DefGlob) String() string { var b strings.Builder for _, e := range g.elems { fmt.Fprint(&b, e) @@ -182,13 +188,13 @@ type element fmt.Stringer // element types. type ( - slash struct{} // One or more '/' separators - literal string // string literal, not containing /, *, ?, {}, or [] - star struct{} // * - anyChar struct{} // ? - starStar struct{} // ** - group []*Glob // {foo, bar, ...} grouping - charRange struct { // [a-z] character range + slash struct{} // One or more '/' separators + literal string // string literal, not containing /, *, ?, {}, or [] + star struct{} // * + anyChar struct{} // ? + starStar struct{} // ** + group []DefGlob // {foo, bar, ...} grouping + charRange struct { // [a-z] character range negate bool low, high rune } @@ -212,7 +218,7 @@ func (r charRange) String() string { } // Match reports whether the input string matches the glob pattern. -func (g *Glob) Match(input string) bool { +func (g DefGlob) Match(input string) bool { return match(g.elems, input) } diff --git a/internal/json/json.go b/internal/json/json.go index 53e01691163..d735ef15c58 100644 --- a/internal/json/json.go +++ b/internal/json/json.go @@ -7,6 +7,7 @@ import ( "github.com/go-json-experiment/json" "github.com/go-json-experiment/json/jsontext" + "github.com/microsoft/typescript-go/internal/typeutil" ) var allowInvalid []json.Options = slices.Clip([]json.Options{jsontext.AllowInvalidUTF8(true)}) @@ -20,7 +21,7 @@ func Marshal(in any, opts ...json.Options) (out []byte, err error) { return json.Marshal(in, opts...) } -func MarshalEncode(out *jsontext.Encoder, in any, opts ...json.Options) (err error) { +func MarshalEncode(out typeutil.DefPtr[jsontext.Encoder], in any, opts ...json.Options) (err error) { if len(opts) == 0 { opts = allowInvalid } else { @@ -29,7 +30,7 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...json.Options) (err err return json.MarshalEncode(out, in, opts...) } -func MarshalWrite(out io.Writer, in any, opts ...json.Options) (err error) { +func MarshalWrite(out io.Writer /* ref: nonnil */, in any, opts ...json.Options) (err error) { if len(opts) == 0 { opts = allowInvalid } else { @@ -46,7 +47,7 @@ func MarshalIndent(in any, prefix, indent string) (out []byte, err error) { return Marshal(in, jsontext.WithIndentPrefix(prefix), jsontext.WithIndent(indent)) } -func MarshalIndentWrite(out io.Writer, in any, prefix, indent string) (err error) { +func MarshalIndentWrite(out io.Writer /* ref: nonnil */, in any, prefix, indent string) (err error) { if prefix == "" && indent == "" { // WithIndentPrefix and WithIndent imply multiline output, so skip them. return MarshalWrite(out, in) @@ -54,15 +55,15 @@ func MarshalIndentWrite(out io.Writer, in any, prefix, indent string) (err error return MarshalWrite(out, in, jsontext.WithIndentPrefix(prefix), jsontext.WithIndent(indent)) } -func Unmarshal(in []byte, out any, opts ...json.Options) (err error) { +func Unmarshal(in []byte, out typeutil.DefAny, opts ...json.Options) (err error) { return json.Unmarshal(in, out, opts...) } -func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...json.Options) (err error) { +func UnmarshalDecode(in typeutil.DefPtr[jsontext.Decoder], out typeutil.DefAny, opts ...json.Options) (err error) { return json.UnmarshalDecode(in, out, opts...) } -func UnmarshalRead(in io.Reader, out any, opts ...json.Options) (err error) { +func UnmarshalRead(in io.Reader /* ref: nonnil */, out typeutil.DefAny, opts ...json.Options) (err error) { return json.UnmarshalRead(in, out, opts...) } @@ -78,8 +79,8 @@ func WithIndent(indent string) json.Options { return jsontext.WithIndent(indent) } -func NewDecoder(r io.Reader) *jsontext.Decoder { - return jsontext.NewDecoder(r) +func NewDecoder(r io.Reader /* ref: nonnil */) typeutil.DefPtr[jsontext.Decoder] { + return typeutil.NonNil(jsontext.NewDecoder(r)) } type ( diff --git a/internal/locale/locale.go b/internal/locale/locale.go index 20d6e14a3de..59edfd227dd 100644 --- a/internal/locale/locale.go +++ b/internal/locale/locale.go @@ -12,11 +12,11 @@ type Locale language.Tag var Default Locale -func WithLocale(ctx context.Context, locale Locale) context.Context { +func WithLocale(ctx context.Context /* ref: nonnil */, locale Locale) context.Context { return context.WithValue(ctx, contextKey(0), locale) } -func FromContext(ctx context.Context) Locale { +func FromContext(ctx context.Context /* ref: nonnil */) Locale { locale, _ := ctx.Value(contextKey(0)).(Locale) return locale } diff --git a/internal/nativepath/eintr_unix.go b/internal/nativepath/eintr_unix.go index 9e2df3108e0..49814c78f10 100644 --- a/internal/nativepath/eintr_unix.go +++ b/internal/nativepath/eintr_unix.go @@ -4,7 +4,7 @@ package nativepath import "syscall" -func ignoringEINTR[T any](fn func() (T, error)) (T, error) { +func ignoringEINTR[T any](fn func() (T, error) /* ref: nonnil */) (T, error) { for { v, err := fn() if err != syscall.EINTR { //nolint:errorlint // syscall functions return raw syscall.Errno, never wrapped diff --git a/internal/pprof/pprof.go b/internal/pprof/pprof.go index bcb68df180e..24ec9f092c4 100644 --- a/internal/pprof/pprof.go +++ b/internal/pprof/pprof.go @@ -19,8 +19,10 @@ type ProfileSession struct { logWriter io.Writer } +type DefProfileSession = *ProfileSession /* ref: nonnil */ + // BeginProfiling starts CPU and memory profiling, writing the profiles to the specified directory. -func BeginProfiling(profileDir string, logWriter io.Writer) *ProfileSession { +func BeginProfiling(profileDir string, logWriter io.Writer) DefProfileSession { if err := os.MkdirAll(profileDir, 0o755); err != nil { panic(err) } @@ -46,7 +48,7 @@ func BeginProfiling(profileDir string, logWriter io.Writer) *ProfileSession { } } -func (p *ProfileSession) Stop() { +func (p DefProfileSession) Stop() { pprof.StopCPUProfile() p.cpuFile.Close() @@ -71,8 +73,10 @@ type CPUProfiler struct { session *ProfileSession } +type DefCPUProfiler = *CPUProfiler /* ref: nonnil */ + // StartCPUProfile starts CPU profiling, writing to the specified directory when stopped. -func (c *CPUProfiler) StartCPUProfile(profileDir string) error { +func (c DefCPUProfiler) StartCPUProfile(profileDir string) error { c.mu.Lock() defer c.mu.Unlock() @@ -105,7 +109,7 @@ func (c *CPUProfiler) StartCPUProfile(profileDir string) error { } // StopCPUProfile stops CPU profiling and returns the path to the profile file. -func (c *CPUProfiler) StopCPUProfile() (string, error) { +func (c DefCPUProfiler) StopCPUProfile() (string, error) { c.mu.Lock() defer c.mu.Unlock() diff --git a/internal/project/background/queue.go b/internal/project/background/queue.go index 26701f425ab..6eca7761fda 100644 --- a/internal/project/background/queue.go +++ b/internal/project/background/queue.go @@ -12,12 +12,17 @@ type Queue struct { closed bool } +type ( + DefQueue = *Queue /* ref: nonnil */ + DefContext = context.Context /* ref: nonnil */ +) + // NewQueue creates a new background queue for managing background tasks execution. -func NewQueue() *Queue { +func NewQueue() DefQueue { return &Queue{} } -func (q *Queue) Enqueue(ctx context.Context, fn func(context.Context)) { +func (q DefQueue) Enqueue(ctx DefContext, fn func(DefContext) /* ref: nonnil */) { q.mu.RLock() if q.closed { q.mu.RUnlock() @@ -41,11 +46,11 @@ func (q *Queue) Enqueue(ctx context.Context, fn func(context.Context)) { // Wait waits for all active tasks to complete. // It does not prevent new tasks from being enqueued while waiting. -func (q *Queue) Wait() { +func (q DefQueue) Wait() { q.wg.Wait() } -func (q *Queue) Close() { +func (q DefQueue) Close() { q.mu.Lock() q.closed = true q.mu.Unlock() diff --git a/internal/project/logging/logcollector.go b/internal/project/logging/logcollector.go index 0870c4e1f81..fe2a91d4d7d 100644 --- a/internal/project/logging/logcollector.go +++ b/internal/project/logging/logcollector.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" "time" + + "github.com/microsoft/typescript-go/internal/typeutil" ) type LogCollector interface { @@ -11,16 +13,20 @@ type LogCollector interface { Logger } +type DefLogCollector = LogCollector /* ref: nonnil */ + type logCollector struct { logger - builder *strings.Builder + builder typeutil.DefPtr[strings.Builder] } -func (lc *logCollector) String() string { +type defLogCollectorImpl = *logCollector /* ref: nonnil */ + +func (lc defLogCollectorImpl) String() string { return lc.builder.String() } -func NewTestLogger() LogCollector { +func NewTestLogger() DefLogCollector { var builder strings.Builder return &logCollector{ logger: logger{ diff --git a/internal/project/logging/logger.go b/internal/project/logging/logger.go index 592649fd05b..453ae8d05c3 100644 --- a/internal/project/logging/logger.go +++ b/internal/project/logging/logger.go @@ -34,13 +34,18 @@ type Logger interface { SetVerbose(verbose bool) } +type ( + DefLogger = Logger /* ref: nonnil */ + DefWriter = io.Writer /* ref: nonnil */ +) + var _ Logger = (*logger)(nil) type logger struct { mu sync.Mutex verbose bool - writer io.Writer - prefix func() string + writer DefWriter + prefix func() string /* ref: nonnil */ } func (l *logger) Log(msg ...any) { @@ -115,7 +120,7 @@ func (l *logger) Infof(format string, args ...any) { l.Logf(format, args...) } -func NewLogger(output io.Writer) Logger { +func NewLogger(output DefWriter) DefLogger { return &logger{ writer: output, prefix: func() string { @@ -126,7 +131,7 @@ func NewLogger(output io.Writer) Logger { // NewNopLogger returns a no-op Logger that discards all log messages. // It is safe to call any method on the returned Logger. -func NewNopLogger() Logger { +func NewNopLogger() DefLogger { return (*logger)(nil) } diff --git a/internal/project/logging/logtree.go b/internal/project/logging/logtree.go index 5c1495fa1a6..f6ff95d0074 100644 --- a/internal/project/logging/logtree.go +++ b/internal/project/logging/logtree.go @@ -6,6 +6,8 @@ import ( "sync" "sync/atomic" "time" + + "github.com/microsoft/typescript-go/internal/typeutil" ) var seq atomic.Uint64 @@ -14,10 +16,16 @@ type logEntry struct { seq uint64 time time.Time message string - child *LogTree + child *InitializedLogTree } -func newLogEntry(child *LogTree, message string) *logEntry { +type ( + defLogEntry = *logEntry /* ref: nonnil */ + InitializedLogTree = LogTree /* ref: struct { root typeutil.DefPtr[LogTree] } */ + DefLogTree = *InitializedLogTree /* ref: nonnil */ +) + +func newLogEntry(child *InitializedLogTree, message string) defLogEntry { return &logEntry{ seq: seq.Add(1), time: time.Now(), @@ -26,12 +34,14 @@ func newLogEntry(child *LogTree, message string) *logEntry { } } -var _ LogCollector = (*LogTree)(nil) +func assertDefLogTreeImplementsLogCollector(tree DefLogTree) { + var _ LogCollector = tree +} type LogTree struct { name string mu sync.Mutex - logs []*logEntry + logs []defLogEntry root *LogTree level int verbose bool @@ -41,15 +51,13 @@ type LogTree struct { stringLength atomic.Int32 } -func NewLogTree(name string) *LogTree { - lc := &LogTree{ - name: name, - } +func NewLogTree(name string) DefLogTree { + lc := &LogTree{name: name} lc.root = lc - return lc + return lc //ref:ignore } -func (c *LogTree) add(log *logEntry) { +func (c DefLogTree) add(log defLogEntry) { // indent + header + message + newline c.root.stringLength.Add(int32(c.level + 15 + len(log.message) + 1)) c.root.count.Add(1) @@ -58,7 +66,7 @@ func (c *LogTree) add(log *logEntry) { c.logs = append(c.logs, log) } -func (c *LogTree) Log(message ...any) { +func (c *InitializedLogTree) Log(message ...any) { if c == nil { return } @@ -66,7 +74,7 @@ func (c *LogTree) Log(message ...any) { c.add(log) } -func (c *LogTree) Logf(format string, args ...any) { +func (c *InitializedLogTree) Logf(format string, args ...any) { if c == nil { return } @@ -74,49 +82,49 @@ func (c *LogTree) Logf(format string, args ...any) { c.add(log) } -func (c *LogTree) IsVerbose() bool { +func (c DefLogTree) IsVerbose() bool { return c.verbose } -func (c *LogTree) SetVerbose(verbose bool) { +func (c *InitializedLogTree) SetVerbose(verbose bool) { if c == nil { return } c.verbose = verbose } -func (c *LogTree) Verbose() Logger { +func (c *InitializedLogTree) Verbose() Logger { if c == nil || !c.verbose { return nil } return c } -func (c *LogTree) Error(msg ...any) { +func (c *InitializedLogTree) Error(msg ...any) { c.Log(msg...) } -func (c *LogTree) Errorf(format string, args ...any) { +func (c *InitializedLogTree) Errorf(format string, args ...any) { c.Logf(format, args...) } -func (c *LogTree) Warn(msg ...any) { +func (c *InitializedLogTree) Warn(msg ...any) { c.Log(msg...) } -func (c *LogTree) Warnf(format string, args ...any) { +func (c *InitializedLogTree) Warnf(format string, args ...any) { c.Logf(format, args...) } -func (c *LogTree) Info(msg ...any) { +func (c *InitializedLogTree) Info(msg ...any) { c.Log(msg...) } -func (c *LogTree) Infof(format string, args ...any) { +func (c *InitializedLogTree) Infof(format string, args ...any) { c.Logf(format, args...) } -func (c *LogTree) Embed(logs *LogTree) { +func (c *InitializedLogTree) Embed(logs DefLogTree) { if c == nil { return } @@ -127,17 +135,17 @@ func (c *LogTree) Embed(logs *LogTree) { c.add(log) } -func (c *LogTree) Fork(message string) *LogTree { +func (c *InitializedLogTree) Fork(message string) *InitializedLogTree { if c == nil { return nil } - child := &LogTree{level: c.level + 1, root: c.root, verbose: c.verbose} + child := &InitializedLogTree{level: c.level + 1, root: c.root, verbose: c.verbose} log := newLogEntry(child, message) c.add(log) return child } -func (c *LogTree) String() string { +func (c DefLogTree) String() string { if c.root != c { panic("can only call String on root LogTree") } @@ -149,7 +157,7 @@ func (c *LogTree) String() string { return builder.String() } -func (c *LogTree) writeLogsRecursive(builder *strings.Builder, indent string) { +func (c DefLogTree) writeLogsRecursive(builder typeutil.DefPtr[strings.Builder], indent string) { for _, log := range c.logs { builder.WriteString(indent) builder.WriteString(formatTime(log.time)) diff --git a/internal/project/logging/logtree_test.go b/internal/project/logging/logtree_test.go index 070e7679cd9..2cc6adfac10 100644 --- a/internal/project/logging/logtree_test.go +++ b/internal/project/logging/logtree_test.go @@ -11,7 +11,10 @@ type testLogger interface { func TestLogTreeImplementsLogger(t *testing.T) { t.Parallel() - var _ testLogger = &LogTree{} +} + +func assertInitializedLogTreeImplementsLogger(tree DefLogTree) { + var _ testLogger = tree } func TestLogTree(t *testing.T) { diff --git a/internal/repo/paths.go b/internal/repo/paths.go index b3838389a02..8b4181723c5 100644 --- a/internal/repo/paths.go +++ b/internal/repo/paths.go @@ -79,7 +79,9 @@ type SkippableTest interface { Skipf(format string, args ...any) } -func SkipIfNoTypeScriptSubmodule(t SkippableTest) { +type DefSkippableTest = SkippableTest /* ref: nonnil */ + +func SkipIfNoTypeScriptSubmodule(t DefSkippableTest) { t.Helper() if !typeScriptSubmoduleExists() { t.Skipf("TypeScript submodule does not exist") diff --git a/internal/semver/version.go b/internal/semver/version.go index 7780551b03c..0539e563f6e 100644 --- a/internal/semver/version.go +++ b/internal/semver/version.go @@ -49,24 +49,26 @@ type Version struct { build []string } +type DefVersion = *Version /* ref: nonnil */ + var versionZero = Version{ prerelease: []string{"0"}, } -func (v *Version) incrementMajor() Version { +func (v DefVersion) incrementMajor() Version { return Version{ major: v.major + 1, } } -func (v *Version) incrementMinor() Version { +func (v DefVersion) incrementMinor() Version { return Version{ major: v.major, minor: v.minor + 1, } } -func (v *Version) incrementPatch() Version { +func (v DefVersion) incrementPatch() Version { return Version{ major: v.major, minor: v.minor, @@ -187,7 +189,7 @@ func comparePreReleaseIdentifier(left, right string) int { return compareResult } -func (v *Version) String() string { +func (v DefVersion) String() string { var sb strings.Builder fmt.Fprintf(&sb, "%d.%d.%d", v.major, v.minor, v.patch) if len(v.prerelease) > 0 { @@ -203,7 +205,9 @@ type SemverParseError struct { origInput string } -func (e *SemverParseError) Error() string { +type DefSemverParseError = *SemverParseError /* ref: nonnil */ + +func (e DefSemverParseError) Error() string { return fmt.Sprintf("Could not parse version string from %q", e.origInput) } diff --git a/internal/semver/version_range.go b/internal/semver/version_range.go index 25ea9b5af2e..86f80cbd773 100644 --- a/internal/semver/version_range.go +++ b/internal/semver/version_range.go @@ -44,6 +44,8 @@ type VersionRange struct { alternatives [][]versionComparator } +type DefVersionRange = *VersionRange /* ref: nonnil */ + type versionComparator struct { operator comparatorOperator operand Version @@ -59,7 +61,7 @@ const ( rangeGreaterThan comparatorOperator = ">" ) -func (v *VersionRange) String() string { +func (v DefVersionRange) String() string { var sb strings.Builder formatDisjunction(&sb, v.alternatives) return sb.String() @@ -94,7 +96,7 @@ func formatComparator(sb *strings.Builder, comparator versionComparator) { sb.WriteString(comparator.operand.String()) } -func (v *VersionRange) Test(version *Version) bool { +func (v DefVersionRange) Test(version *Version) bool { return testDisjunction(v.alternatives, version) } diff --git a/internal/testutil/filefixture/filefixture.go b/internal/testutil/filefixture/filefixture.go index c13485ee8a6..47cbb86c3dc 100644 --- a/internal/testutil/filefixture/filefixture.go +++ b/internal/testutil/filefixture/filefixture.go @@ -13,13 +13,17 @@ type Fixture interface { ReadFile(t testing.TB) string } +type DefFixture = Fixture /* ref: nonnil */ + type fromFile struct { name string path string - contents func() (string, error) + contents func() (string, error) /* ref: nonnil */ } -func FromFile(name string, path string) Fixture { +type defFromFile = *fromFile /* ref: nonnil */ + +func FromFile(name string, path string) DefFixture { return &fromFile{ name: name, path: path, @@ -31,10 +35,10 @@ func FromFile(name string, path string) Fixture { } } -func (f *fromFile) Name() string { return f.name } -func (f *fromFile) Path() string { return f.path } +func (f defFromFile) Name() string { return f.name } +func (f defFromFile) Path() string { return f.path } -func (f *fromFile) SkipIfNotExist(tb testing.TB) { +func (f defFromFile) SkipIfNotExist(tb testing.TB) { tb.Helper() if _, err := os.Stat(f.path); err != nil { @@ -42,7 +46,7 @@ func (f *fromFile) SkipIfNotExist(tb testing.TB) { } } -func (f *fromFile) ReadFile(tb testing.TB) string { +func (f defFromFile) ReadFile(tb testing.TB) string { tb.Helper() contents, err := f.contents() @@ -58,7 +62,9 @@ type fromString struct { contents string } -func FromString(name string, path string, contents string) Fixture { +type defFromString = *fromString /* ref: nonnil */ + +func FromString(name string, path string, contents string) DefFixture { return &fromString{ name: name, path: path, @@ -66,9 +72,9 @@ func FromString(name string, path string, contents string) Fixture { } } -func (f *fromString) Name() string { return f.name } -func (f *fromString) Path() string { return f.path } +func (f defFromString) Name() string { return f.name } +func (f defFromString) Path() string { return f.path } -func (f *fromString) SkipIfNotExist(tb testing.TB) {} +func (f defFromString) SkipIfNotExist(tb testing.TB) {} -func (f *fromString) ReadFile(tb testing.TB) string { return f.contents } +func (f defFromString) ReadFile(tb testing.TB) string { return f.contents } diff --git a/internal/typeutil/typeutil.go b/internal/typeutil/typeutil.go new file mode 100644 index 00000000000..91b3c8f1508 --- /dev/null +++ b/internal/typeutil/typeutil.go @@ -0,0 +1,16 @@ +package typeutil + +type ( + DefPtr[T any] = *T // ref: nonnil + DefSlice[T any] = []T // ref: nonnil + DefMap[K comparable, V any] = map[K]V // ref: nonnil + Never = any // ref: never + DefAny = any // ref: nonnil + DefError = error // ref: nonnil + UnusedAny = any // Import and use this type whenever you would use one of these types only in a refinement annoation. +) + +// Asserts `x` is non-nil. Equivalent to `x!` in TS. +func NonNil[T any](x *T) DefPtr[T] { + return x //ref:ignore +} diff --git a/internal/vfs/osvfs/os.go b/internal/vfs/osvfs/os.go index 7db6f338b82..c939ec20fd0 100644 --- a/internal/vfs/osvfs/os.go +++ b/internal/vfs/osvfs/os.go @@ -28,11 +28,11 @@ var ( ) // FS creates a new FS from the OS file system. -func FS() vfs.FS { +func FS() vfs.DefFS { return osVFS } -var osVFS vfs.FS = &osFS{ +var osVFS vfs.DefFS = &osFS{ common: internal.Common{ RootFor: os.DirFS, IsReparsePoint: isReparsePoint, diff --git a/internal/vfs/vfs.go b/internal/vfs/vfs.go index 7690fa3d650..d0cad4e0a66 100644 --- a/internal/vfs/vfs.go +++ b/internal/vfs/vfs.go @@ -49,6 +49,8 @@ type FS interface { Realpath(path string) string } +type DefFS = FS /* ref: nonnil */ + type Entries struct { Files []string Directories []string diff --git a/internal/vfs/vfs_test.go b/internal/vfs/vfs_test.go index 58787fb6e61..7fc212d3ca4 100644 --- a/internal/vfs/vfs_test.go +++ b/internal/vfs/vfs_test.go @@ -15,7 +15,7 @@ import ( func BenchmarkReadFile(b *testing.B) { type bench struct { name string - fs vfs.FS + fs vfs.DefFS path string } diff --git a/internal/vfs/vfstest/vfstest.go b/internal/vfs/vfstest/vfstest.go index e4945503a93..213a1fbd02d 100644 --- a/internal/vfs/vfstest/vfstest.go +++ b/internal/vfs/vfstest/vfstest.go @@ -67,7 +67,7 @@ type sys struct { // The paths must be normalized absolute paths according to the tspath package, // without trailing directory separators. // The paths must be all POSIX-style or all Windows-style, but not both. -func FromMap[File any](m map[string]File, useCaseSensitiveFileNames bool) vfs.FS { +func FromMap[File any](m map[string]File, useCaseSensitiveFileNames bool) vfs.DefFS { return FromMapWithClock(m, useCaseSensitiveFileNames, &clockImpl{start: time.Now()}) } @@ -77,7 +77,7 @@ func FromMap[File any](m map[string]File, useCaseSensitiveFileNames bool) vfs.FS // The paths must be normalized absolute paths according to the tspath package, // without trailing directory separators. // The paths must be all POSIX-style or all Windows-style, but not both. -func FromMapWithClock[File any](m map[string]File, useCaseSensitiveFileNames bool, clock Clock) vfs.FS { +func FromMapWithClock[File any](m map[string]File, useCaseSensitiveFileNames bool, clock Clock) vfs.DefFS { posix := false windows := false