Skip to content

Commit 903e689

Browse files
committed
gopls/internal/lsp/source/completion: start timing before type checking
Partially revert CL 503016, to go back to starting the completion timer before type checking. As discussed in slack and golang/go#62665, even if this leads to inconsistent behavior across various LSP clients (due to order of requests) we should still do our best to interpret the completion budget from the user perspective. For golang/go#62665 Change-Id: I2035e2ecb7776cead7a19bd37b9df512fdbf3d17 Reviewed-on: https://go-review.googlesource.com/c/tools/+/530016 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Alan Donovan <adonovan@google.com>
1 parent 455b761 commit 903e689

File tree

2 files changed

+19
-8
lines changed

2 files changed

+19
-8
lines changed

gopls/internal/lsp/source/completion/completion.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,15 @@ type completer struct {
232232
// mapper converts the positions in the file from which the completion originated.
233233
mapper *protocol.Mapper
234234

235+
// startTime is when we started processing this completion request. It does
236+
// not include any time the request spent in the queue.
237+
//
238+
// Note: in CL 503016, startTime move to *after* type checking, but it was
239+
// subsequently determined that it was better to keep setting it *before*
240+
// type checking, so that the completion budget best approximates the user
241+
// experience. See golang/go#62665 for more details.
242+
startTime time.Time
243+
235244
// scopes contains all scopes defined by nodes in our path,
236245
// including nil values for nodes that don't defined a scope. It
237246
// also includes our package scope and the universal scope at the
@@ -437,6 +446,8 @@ func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHan
437446
ctx, done := event.Start(ctx, "completion.Completion")
438447
defer done()
439448

449+
startTime := time.Now()
450+
440451
pkg, pgf, err := source.NarrowestPackageForFile(ctx, snapshot, fh.URI())
441452
if err != nil || pgf.File.Package == token.NoPos {
442453
// If we can't parse this file or find position for the package
@@ -451,6 +462,7 @@ func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHan
451462
}
452463
return items, surrounding, nil
453464
}
465+
454466
pos, err := pgf.PositionPos(protoPos)
455467
if err != nil {
456468
return nil, nil, err
@@ -545,10 +557,12 @@ func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHan
545557
matcher: prefixMatcher(""),
546558
methodSetCache: make(map[methodSetKey]*types.MethodSet),
547559
mapper: pgf.Mapper,
560+
startTime: startTime,
548561
scopes: scopes,
549562
}
550563

551564
ctx, cancel := context.WithCancel(ctx)
565+
defer cancel()
552566

553567
// Compute the deadline for this operation. Deadline is relative to the
554568
// search operation, not the entire completion RPC, as the work up until this
@@ -562,15 +576,12 @@ func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHan
562576
// Don't overload the context with this deadline, as we don't want to
563577
// conflate user cancellation (=fail the operation) with our time limit
564578
// (=stop searching and succeed with partial results).
565-
start := time.Now()
566579
var deadline *time.Time
567580
if c.opts.budget > 0 {
568-
d := start.Add(c.opts.budget)
581+
d := startTime.Add(c.opts.budget)
569582
deadline = &d
570583
}
571584

572-
defer cancel()
573-
574585
if surrounding := c.containingIdent(pgf.Src); surrounding != nil {
575586
c.setSurrounding(surrounding)
576587
}
@@ -583,7 +594,7 @@ func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHan
583594
}
584595

585596
// Deep search collected candidates and their members for more candidates.
586-
c.deepSearch(ctx, start, deadline)
597+
c.deepSearch(ctx, deadline)
587598

588599
for _, callback := range c.completionCallbacks {
589600
if err := c.snapshot.RunProcessEnvFunc(ctx, callback); err != nil {
@@ -593,7 +604,7 @@ func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHan
593604

594605
// Search candidates populated by expensive operations like
595606
// unimportedMembers etc. for more completion items.
596-
c.deepSearch(ctx, start, deadline)
607+
c.deepSearch(ctx, deadline)
597608

598609
// Statement candidates offer an entire statement in certain contexts, as
599610
// opposed to a single object. Add statement candidates last because they

gopls/internal/lsp/source/completion/deep_completion.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func (s *deepCompletionState) newPath(cand candidate, obj types.Object) []types.
113113
// deepSearch searches a candidate and its subordinate objects for completion
114114
// items if deep completion is enabled and adds the valid candidates to
115115
// completion items.
116-
func (c *completer) deepSearch(ctx context.Context, start time.Time, deadline *time.Time) {
116+
func (c *completer) deepSearch(ctx context.Context, deadline *time.Time) {
117117
defer func() {
118118
// We can return early before completing the search, so be sure to
119119
// clear out our queues to not impact any further invocations.
@@ -172,7 +172,7 @@ func (c *completer) deepSearch(ctx context.Context, start time.Time, deadline *t
172172

173173
c.deepState.candidateCount++
174174
if c.opts.budget > 0 && c.deepState.candidateCount%100 == 0 {
175-
spent := float64(time.Since(start)) / float64(c.opts.budget)
175+
spent := float64(time.Since(c.startTime)) / float64(c.opts.budget)
176176
select {
177177
case <-ctx.Done():
178178
return

0 commit comments

Comments
 (0)