Repository: go-delve/delve
Pull request #2472 (2021-05-10 08:47:27)

service/dap: support setting breakpoints while running
Unlike vscode-go, this implementation does not resume execution after halting and setting breakpoints. Resuming automatically turns out to be much trickier than just skipping a stopped event and continuing. It is possible that the stop occurred due to reasons other than our manual stop (breakpoint, call return), so we would need to detect thtat and report any stops that the user might be interested in. In addition, next would be cancelled by the halt command, so to resume it, we would need to implement an alternative version of halt that doesn't cancel next. So for now, we will just be reporting the pause to the user and let them decide when and how to resume execution manually.

Updates #1515
Updates https://github.com/golang/vscode-go/issues/1475



Patch:
diff --git a/pkg/gobuild/gobuild.go b/pkg/gobuild/gobuild.go
index 0f3cc051..bf571180 100644
--- a/pkg/gobuild/gobuild.go
+++ b/pkg/gobuild/gobuild.go
@@ -7,6 +7,7 @@ import (
 	"os"
 	"os/exec"
 	"runtime"
+	"strings"
 	"time"
 
 	"github.com/go-delve/delve/pkg/config"
@@ -60,7 +61,7 @@ func GoBuild(debugname string, pkgs []string, buildflags string) error {
 
 // GoBuildCombinedOutput builds non-test files in 'pkgs' with the specified 'buildflags'
 // and writes the output at 'debugname'.
-func GoBuildCombinedOutput(debugname string, pkgs []string, buildflags string) ([]byte, error) {
+func GoBuildCombinedOutput(debugname string, pkgs []string, buildflags string) (string, []byte, error) {
 	args := goBuildArgs(debugname, pkgs, buildflags, false)
 	return gocommandCombinedOutput("build", args...)
 }
@@ -74,7 +75,7 @@ func GoTestBuild(debugname string, pkgs []string, buildflags string) error {
 
 // GoTestBuildCombinedOutput builds test files 'pkgs' with the specified 'buildflags'
 // and writes the output at 'debugname'.
-func GoTestBuildCombinedOutput(debugname string, pkgs []string, buildflags string) ([]byte, error) {
+func GoTestBuildCombinedOutput(debugname string, pkgs []string, buildflags string) (string, []byte, error) {
 	args := goBuildArgs(debugname, pkgs, buildflags, true)
 	return gocommandCombinedOutput("test", args...)
 }
@@ -93,19 +94,21 @@ func goBuildArgs(debugname string, pkgs []string, buildflags string, isTest bool
 }
 
 func gocommandRun(command string, args ...string) error {
-	goBuild := gocommandExecCmd(command, args...)
+	_, goBuild := gocommandExecCmd(command, args...)
 	goBuild.Stderr = os.Stdout
 	goBuild.Stdout = os.Stderr
 	return goBuild.Run()
 }
 
-func gocommandCombinedOutput(command string, args ...string) ([]byte, error) {
-	return gocommandExecCmd(command, args...).CombinedOutput()
+func gocommandCombinedOutput(command string, args ...string) (string, []byte, error) {
+	buildCmd, goBuild := gocommandExecCmd(command, args...)
+	out, err := goBuild.CombinedOutput()
+	return buildCmd, out, err
 }
 
-func gocommandExecCmd(command string, args ...string) *exec.Cmd {
+func gocommandExecCmd(command string, args ...string) (string, *exec.Cmd) {
 	allargs := []string{command}
 	allargs = append(allargs, args...)
 	goBuild := exec.Command("go", allargs...)
-	return goBuild
+	return strings.Join(append([]string{"go"}, allargs...), " "), goBuild
 }
diff --git a/pkg/proc/pe.go b/pkg/proc/pe.go
index 44d0eaef..6295f8f8 100644
--- a/pkg/proc/pe.go
+++ b/pkg/proc/pe.go
@@ -62,5 +62,5 @@ func (m _PEMachine) String() string {
 	if ok {
 		return str
 	}
-	return fmt.Sprintf("unkown image file machine code %d\n", uint16(m))
+	return fmt.Sprintf("unknown image file machine code %d\n", uint16(m))
 }
diff --git a/pkg/proc/target.go b/pkg/proc/target.go
index b8732007..a923bec6 100644
--- a/pkg/proc/target.go
+++ b/pkg/proc/target.go
@@ -84,7 +84,7 @@ type StopReason uint8
 func (sr StopReason) String() string {
 	switch sr {
 	case StopUnknown:
-		return "unkown"
+		return "unknown"
 	case StopLaunched:
 		return "launched"
 	case StopAttached:
diff --git a/pkg/proc/variables.go b/pkg/proc/variables.go
index 098695f5..2926dc67 100644
--- a/pkg/proc/variables.go
+++ b/pkg/proc/variables.go
@@ -755,10 +755,20 @@ func (v *Variable) TypeString() string {
 	if v == nilVariable {
 		return "nil"
 	}
-	if v.DwarfType != nil {
+	if v.DwarfType == nil {
+		return v.Kind.String()
+	}
+	if v.DwarfType.Common().Name != "" {
 		return v.DwarfType.Common().Name
 	}
-	return v.Kind.String()
+	r := v.DwarfType.String()
+	if r == "*void" {
+		cu := v.bi.Images[v.DwarfType.Common().Index].findCompileUnitForOffset(v.DwarfType.Common().Offset)
+		if cu != nil && cu.isgo {
+			r = "unsafe.Pointer"
+		}
+	}
+	return r
 }
 
 func (v *Variable) toField(field *godwarf.StructField) (*Variable, error) {
diff --git a/service/dap/server.go b/service/dap/server.go
index a444f4b2..68c983ab 100644
--- a/service/dap/server.go
+++ b/service/dap/server.go
@@ -102,6 +102,8 @@ type Server struct {
 	variableHandles *variablesHandlesMap
 	// args tracks special settings for handling debug session requests.
 	args launchAttachArgs
+	// clientCapabilities tracks special settings for handling debug session requests.
+	clientCapabilities dapClientCapabilites
 
 	// mu synchronizes access to objects set on start-up (from run goroutine)
 	// and stopped on teardown (from main goroutine)
@@ -147,6 +149,16 @@ var defaultArgs = launchAttachArgs{
 	substitutePathServerToClient: [][2]string{},
 }
 
+// dapClientCapabilites captures arguments from intitialize request that
+// impact handling of subsequent requests.
+type dapClientCapabilites struct {
+	supportsVariableType         bool
+	supportsVariablePaging       bool
+	supportsRunInTerminalRequest bool
+	supportsMemoryReferences     bool
+	supportsProgressReporting    bool
+}
+
 // DefaultLoadConfig controls how variables are loaded from the target's memory, borrowing the
 // default value from the original vscode-go debug adapter and rpc server.
 // With dlv-dap, users currently do not have a way to adjust these.
@@ -387,8 +399,7 @@ func (s *Server) handleRequest(request dap.Message) {
 	// We have a couple of options for handling these without blocking
 	// the request loop indefinitely when we are in running state.
 	// --1-- Return a dummy response or an error right away.
-	// --2-- Halt execution, process the request, resume execution.
-	// TODO(polina): do this for setting breakpoints
+	// --2-- Halt execution, process the request, maybe resume execution.
 	// --3-- Handle such requests asynchronously and let them block until
 	// the process stops or terminates (e.g. using a channel and a single
 	// goroutine to preserve the order). This might not be appropriate
@@ -415,6 +426,28 @@ func (s *Server) handleRequest(request dap.Message) {
 				Body:     dap.ThreadsResponseBody{Threads: []dap.Thread{{Id: -1, Name: "Current"}}},
 			}
 			s.send(response)
+		case *dap.SetBreakpointsRequest:
+			s.log.Debug("halting execution to set breakpoints")
+			_, err := s.debugger.Command(&api.DebuggerCommand{Name: api.Halt}, nil)
+			if err != nil {
+				s.sendErrorResponse(request.Request, UnableToSetBreakpoints, "Unable to set or clear breakpoints", err.Error())
+				return
+			}
+			s.onSetBreakpointsRequest(request)
+			// TODO(polina): consider resuming execution here automatically after suppressing
+			// a stop event when an operation in doRunCommand returns. In case that operation
+			// was already stopping for a different reason, we would need to examine the state
+			// that is returned to determine if this halt was the cause of the stop or not.
+			// We should stop with an event and not resume if one of the following is true:
+			// - StopReason is anything but manual
+			// - Any thread has a breakpoint or CallReturn set
+			// - NextInProgress is false and the last command sent by the user was: next,
+			//   step, stepOut, reverseNext, reverseStep or reverseStepOut
+			// Otherwise, we can skip the stop event and resume the temporarily
+			// interrupted process execution with api.DirectionCongruentContinue.
+			// For this to apply in cases other than api.Continue, we would also need to
+			// introduce a new version of halt that skips ClearInternalBreakpoints
+			// in proc.(*Target).Continue, leaving NextInProgress as true.
 		default:
 			r := request.(dap.RequestMessage).GetRequest()
 			s.sendErrorResponse(*r, DebuggeeIsRunning, fmt.Sprintf("Unable to process `%s`", r.Command), "debuggee is running")
@@ -608,6 +641,7 @@ func (s *Server) logToConsole(msg string) {
 }
 
 func (s *Server) onInitializeRequest(request *dap.InitializeRequest) {
+	s.setClientCapabilities(request.Arguments)
 	if request.Arguments.PathFormat != "path" {
 		s.sendErrorResponse(request.Request, FailedToInitialize, "Failed to initialize",
 			fmt.Sprintf("Unsupported 'pathFormat' value '%s'.", request.Arguments.PathFormat))
@@ -645,6 +679,14 @@ func (s *Server) onInitializeRequest(request *dap.InitializeRequest) {
 	s.send(response)
 }
 
+func (s *Server) setClientCapabilities(args dap.InitializeRequestArguments) {
+	s.clientCapabilities.supportsMemoryReferences = args.SupportsMemoryReferences
+	s.clientCapabilities.supportsProgressReporting = args.SupportsProgressReporting
+	s.clientCapabilities.supportsRunInTerminalRequest = args.SupportsRunInTerminalRequest
+	s.clientCapabilities.supportsVariablePaging = args.SupportsVariablePaging
+	s.clientCapabilities.supportsVariableType = args.SupportsVariableType
+}
+
 // Default output file pathname for the compiled binary in debug or test modes,
 // relative to the current working directory of the server.
 const defaultDebugBinary string = "./__debug_bin"
@@ -702,17 +744,24 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
 		}
 
 		s.log.Debugf("building binary at %s", debugbinary)
+		var cmd string
 		var out []byte
 		switch mode {
 		case "debug":
-			out, err = gobuild.GoBuildCombinedOutput(debugbinary, []string{program}, buildFlags)
+			cmd, out, err = gobuild.GoBuildCombinedOutput(debugbinary, []string{program}, buildFlags)
 		case "test":
-			out, err = gobuild.GoTestBuildCombinedOutput(debugbinary, []string{program}, buildFlags)
+			cmd, out, err = gobuild.GoTestBuildCombinedOutput(debugbinary, []string{program}, buildFlags)
 		}
 		if err != nil {
+			s.send(&dap.OutputEvent{
+				Event: *newEvent("output"),
+				Body: dap.OutputEventBody{
+					Output:   fmt.Sprintf("Build Error: %s\n%s (%s)\n", cmd, strings.TrimSpace(string(out)), err.Error()),
+					Category: "stderr",
+				}})
 			s.sendErrorResponse(request.Request,
 				FailedToLaunch, "Failed to launch",
-				fmt.Sprintf("Build error: %s (%s)", strings.TrimSpace(string(out)), err.Error()))
+				"Build error: Check the debug console for details.")
 			return
 		}
 		program = debugbinary
@@ -1037,7 +1086,7 @@ func (s *Server) onConfigurationDoneRequest(request *dap.ConfigurationDoneReques
 	}
 	s.send(&dap.ConfigurationDoneResponse{Response: *newResponse(request.Request)})
 	if !s.args.stopOnEntry {
-		s.doCommand(api.Continue, asyncSetupDone)
+		s.doRunCommand(api.Continue, asyncSetupDone)
 	}
 }
 
@@ -1047,7 +1096,7 @@ func (s *Server) onContinueRequest(request *dap.ContinueRequest, asyncSetupDone
 	s.send(&dap.ContinueResponse{
 		Response: *newResponse(request.Request),
 		Body:     dap.ContinueResponseBody{AllThreadsContinued: true}})
-	s.doCommand(api.Continue, asyncSetupDone)
+	s.doRunCommand(api.Continue, asyncSetupDone)
 }
 
 func fnName(loc *proc.Location) string {
@@ -1193,7 +1242,7 @@ func stoppedGoroutineID(state *api.DebuggerState) (id int) {
 	return id
 }
 
-// doStepCommand is a wrapper around doCommand that
+// doStepCommand is a wrapper around doRunCommand that
 // first switches selected goroutine. asyncSetupDone is
 // a channel that will be closed to signal that an
 // asynchornous command has completed setup or was interrupted
@@ -1217,7 +1266,7 @@ func (s *Server) doStepCommand(command string, threadId int, asyncSetupDone chan
 		s.send(stopped)
 		return
 	}
-	s.doCommand(command, asyncSetupDone)
+	s.doRunCommand(command, asyncSetupDone)
 }
 
 // onPauseRequest sends a not-yet-implemented error response.
@@ -1390,6 +1439,8 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
 			}
 			key, keyref := s.convertVariable(keyv, keyexpr)
 			val, valref := s.convertVariable(valv, valexpr)
+			keyType := s.getTypeIfSupported(keyv)
+			valType := s.getTypeIfSupported(valv)
 			// If key or value or both are scalars, we can use
 			// a single variable to represet key:value format.
 			// Otherwise, we must return separate variables for both.
@@ -1397,20 +1448,27 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
 				keyvar := dap.Variable{
 					Name:               fmt.Sprintf("[key %d]", kvIndex),
 					EvaluateName:       keyexpr,
+					Type:               keyType,
 					Value:              key,
 					VariablesReference: keyref,
 				}
 				valvar := dap.Variable{
 					Name:               fmt.Sprintf("[val %d]", kvIndex),
 					EvaluateName:       valexpr,
+					Type:               valType,
 					Value:              val,
 					VariablesReference: valref,
 				}
 				children = append(children, keyvar, valvar)
 			} else { // At least one is a scalar
+				keyValType := valType
+				if len(keyType) > 0 && len(valType) > 0 {
+					keyValType = fmt.Sprintf("%s: %s", keyType, valType)
+				}
 				kvvar := dap.Variable{
 					Name:         key,
 					EvaluateName: valexpr,
+					Type:         keyValType,
 					Value:        val,
 				}
 				if keyref != 0 { // key is a type to be expanded
@@ -1433,6 +1491,7 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
 			children[i] = dap.Variable{
 				Name:               fmt.Sprintf("[%d]", i),
 				EvaluateName:       cfqname,
+				Type:               s.getTypeIfSupported(&v.Children[i]),
 				Value:              cvalue,
 				VariablesReference: cvarref,
 			}
@@ -1470,11 +1529,19 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
 			children[i] = dap.Variable{
 				Name:               name,
 				EvaluateName:       cfqname,
+				Type:               s.getTypeIfSupported(c),
 				Value:              cvalue,
 				VariablesReference: cvarref,
 			}
 		}
 	}
+	if !s.clientCapabilities.supportsVariableType {
+		// If the client does not support variable type
+		// we cannot set the Type field in the response.
+		for i := range children {
+			children[i].Type = ""
+		}
+	}
 	response := &dap.VariablesResponse{
 		Response: *newResponse(request.Request),
 		Body:     dap.VariablesResponseBody{Variables: children},
@@ -1482,6 +1549,13 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
 	s.send(response)
 }
 
+func (s *Server) getTypeIfSupported(v *proc.Variable) string {
+	if !s.clientCapabilities.supportsVariableType {
+		return ""
+	}
+	return v.TypeString()
+}
+
 // convertVariable converts proc.Variable to dap.Variable value and reference
 // while keeping track of the full qualified name or load expression.
 // Variable reference is used to keep track of the children associated with each
@@ -1905,14 +1979,14 @@ func (s *Server) resetHandlesForStoppedEvent() {
 	s.variableHandles.reset()
 }
 
-// doCommand runs a debugger command until it stops on
+// doRunCommand runs a debugger command until it stops on
 // termination, error, breakpoint, etc, when an appropriate
 // event needs to be sent to the client. asyncSetupDone is
 // a channel that will be closed to signal that an
 // asynchornous command has completed setup or was interrupted
 // due to an error, so the server is ready to receive new requests.
-func (s *Server) doCommand(command string, asyncSetupDone chan struct{}) {
-	// TODO(polina): it appears that debugger.Command doesn't close
+func (s *Server) doRunCommand(command string, asyncSetupDone chan struct{}) {
+	// TODO(polina): it appears that debugger.Command doesn't always close
 	// asyncSetupDone (e.g. when having an error next while nexting).
 	// So we should always close it ourselves just in case.
 	defer s.asyncCommandDone(asyncSetupDone)
@@ -1922,6 +1996,9 @@ func (s *Server) doCommand(command string, asyncSetupDone chan struct{}) {
 		return
 	}
 
+	stopReason := s.debugger.StopReason()
+	s.log.Debugf("%q command stopped - reason %q", command, stopReason)
+
 	s.resetHandlesForStoppedEvent()
 	stopped := &dap.StoppedEvent{Event: *newEvent("stopped")}
 	stopped.Body.AllThreadsStopped = true
@@ -1929,9 +2006,7 @@ func (s *Server) doCommand(command string, asyncSetupDone chan struct{}) {
 	if err == nil {
 		stopped.Body.ThreadId = stoppedGoroutineID(state)
 
-		sr := s.debugger.StopReason()
-		s.log.Debugf("%q command stopped - reason %q", command, sr)
-		switch sr {
+		switch stopReason {
 		case proc.StopNextFinished:
 			stopped.Body.Reason = "step"
 		case proc.StopManual: // triggered by halt


Test patch:
diff --git a/service/dap/daptest/gen/main.go b/service/dap/daptest/gen/main.go
index 41aa002a..14781af4 100644
--- a/service/dap/daptest/gen/main.go
+++ b/service/dap/daptest/gen/main.go
@@ -36,7 +36,7 @@ func (c *Client) Expect{{.}}(t *testing.T) *dap.{{.}} {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.{{.}})
 	if !ok {
-		t.Fatalf("got %q, want *dap.{{.}}", m)
+		t.Fatalf("got %#v, want *dap.{{.}}", m)
 	}
 	return r
 }{{end}}
diff --git a/service/dap/daptest/resp.go b/service/dap/daptest/resp.go
index 086455ba..7002afdd 100644
--- a/service/dap/daptest/resp.go
+++ b/service/dap/daptest/resp.go
@@ -16,7 +16,7 @@ func (c *Client) ExpectAttachResponse(t *testing.T) *dap.AttachResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.AttachResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.AttachResponse", m)
+		t.Fatalf("got %#v, want *dap.AttachResponse", m)
 	}
 	return r
 }
@@ -28,7 +28,7 @@ func (c *Client) ExpectBreakpointEvent(t *testing.T) *dap.BreakpointEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.BreakpointEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.BreakpointEvent", m)
+		t.Fatalf("got %#v, want *dap.BreakpointEvent", m)
 	}
 	return r
 }
@@ -40,7 +40,7 @@ func (c *Client) ExpectBreakpointLocationsResponse(t *testing.T) *dap.Breakpoint
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.BreakpointLocationsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.BreakpointLocationsResponse", m)
+		t.Fatalf("got %#v, want *dap.BreakpointLocationsResponse", m)
 	}
 	return r
 }
@@ -52,7 +52,7 @@ func (c *Client) ExpectCancelResponse(t *testing.T) *dap.CancelResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.CancelResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.CancelResponse", m)
+		t.Fatalf("got %#v, want *dap.CancelResponse", m)
 	}
 	return r
 }
@@ -64,7 +64,7 @@ func (c *Client) ExpectCapabilitiesEvent(t *testing.T) *dap.CapabilitiesEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.CapabilitiesEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.CapabilitiesEvent", m)
+		t.Fatalf("got %#v, want *dap.CapabilitiesEvent", m)
 	}
 	return r
 }
@@ -76,7 +76,7 @@ func (c *Client) ExpectCompletionsResponse(t *testing.T) *dap.CompletionsRespons
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.CompletionsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.CompletionsResponse", m)
+		t.Fatalf("got %#v, want *dap.CompletionsResponse", m)
 	}
 	return r
 }
@@ -88,7 +88,7 @@ func (c *Client) ExpectConfigurationDoneResponse(t *testing.T) *dap.Configuratio
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ConfigurationDoneResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ConfigurationDoneResponse", m)
+		t.Fatalf("got %#v, want *dap.ConfigurationDoneResponse", m)
 	}
 	return r
 }
@@ -100,7 +100,7 @@ func (c *Client) ExpectContinueResponse(t *testing.T) *dap.ContinueResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ContinueResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ContinueResponse", m)
+		t.Fatalf("got %#v, want *dap.ContinueResponse", m)
 	}
 	return r
 }
@@ -112,7 +112,7 @@ func (c *Client) ExpectContinuedEvent(t *testing.T) *dap.ContinuedEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ContinuedEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ContinuedEvent", m)
+		t.Fatalf("got %#v, want *dap.ContinuedEvent", m)
 	}
 	return r
 }
@@ -124,7 +124,7 @@ func (c *Client) ExpectDataBreakpointInfoResponse(t *testing.T) *dap.DataBreakpo
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.DataBreakpointInfoResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.DataBreakpointInfoResponse", m)
+		t.Fatalf("got %#v, want *dap.DataBreakpointInfoResponse", m)
 	}
 	return r
 }
@@ -136,7 +136,7 @@ func (c *Client) ExpectDisassembleResponse(t *testing.T) *dap.DisassembleRespons
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.DisassembleResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.DisassembleResponse", m)
+		t.Fatalf("got %#v, want *dap.DisassembleResponse", m)
 	}
 	return r
 }
@@ -148,7 +148,7 @@ func (c *Client) ExpectDisconnectResponse(t *testing.T) *dap.DisconnectResponse
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.DisconnectResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.DisconnectResponse", m)
+		t.Fatalf("got %#v, want *dap.DisconnectResponse", m)
 	}
 	return r
 }
@@ -160,7 +160,7 @@ func (c *Client) ExpectErrorResponse(t *testing.T) *dap.ErrorResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ErrorResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ErrorResponse", m)
+		t.Fatalf("got %#v, want *dap.ErrorResponse", m)
 	}
 	return r
 }
@@ -172,7 +172,7 @@ func (c *Client) ExpectEvaluateResponse(t *testing.T) *dap.EvaluateResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.EvaluateResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.EvaluateResponse", m)
+		t.Fatalf("got %#v, want *dap.EvaluateResponse", m)
 	}
 	return r
 }
@@ -184,7 +184,7 @@ func (c *Client) ExpectExceptionInfoResponse(t *testing.T) *dap.ExceptionInfoRes
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ExceptionInfoResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ExceptionInfoResponse", m)
+		t.Fatalf("got %#v, want *dap.ExceptionInfoResponse", m)
 	}
 	return r
 }
@@ -196,7 +196,7 @@ func (c *Client) ExpectExitedEvent(t *testing.T) *dap.ExitedEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ExitedEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ExitedEvent", m)
+		t.Fatalf("got %#v, want *dap.ExitedEvent", m)
 	}
 	return r
 }
@@ -208,7 +208,7 @@ func (c *Client) ExpectGotoResponse(t *testing.T) *dap.GotoResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.GotoResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.GotoResponse", m)
+		t.Fatalf("got %#v, want *dap.GotoResponse", m)
 	}
 	return r
 }
@@ -220,7 +220,7 @@ func (c *Client) ExpectGotoTargetsResponse(t *testing.T) *dap.GotoTargetsRespons
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.GotoTargetsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.GotoTargetsResponse", m)
+		t.Fatalf("got %#v, want *dap.GotoTargetsResponse", m)
 	}
 	return r
 }
@@ -232,7 +232,7 @@ func (c *Client) ExpectInitializeResponse(t *testing.T) *dap.InitializeResponse
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.InitializeResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.InitializeResponse", m)
+		t.Fatalf("got %#v, want *dap.InitializeResponse", m)
 	}
 	return r
 }
@@ -244,7 +244,7 @@ func (c *Client) ExpectInitializedEvent(t *testing.T) *dap.InitializedEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.InitializedEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.InitializedEvent", m)
+		t.Fatalf("got %#v, want *dap.InitializedEvent", m)
 	}
 	return r
 }
@@ -256,7 +256,7 @@ func (c *Client) ExpectInvalidatedEvent(t *testing.T) *dap.InvalidatedEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.InvalidatedEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.InvalidatedEvent", m)
+		t.Fatalf("got %#v, want *dap.InvalidatedEvent", m)
 	}
 	return r
 }
@@ -268,7 +268,7 @@ func (c *Client) ExpectLaunchResponse(t *testing.T) *dap.LaunchResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.LaunchResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.LaunchResponse", m)
+		t.Fatalf("got %#v, want *dap.LaunchResponse", m)
 	}
 	return r
 }
@@ -280,7 +280,7 @@ func (c *Client) ExpectLoadedSourceEvent(t *testing.T) *dap.LoadedSourceEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.LoadedSourceEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.LoadedSourceEvent", m)
+		t.Fatalf("got %#v, want *dap.LoadedSourceEvent", m)
 	}
 	return r
 }
@@ -292,7 +292,7 @@ func (c *Client) ExpectLoadedSourcesResponse(t *testing.T) *dap.LoadedSourcesRes
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.LoadedSourcesResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.LoadedSourcesResponse", m)
+		t.Fatalf("got %#v, want *dap.LoadedSourcesResponse", m)
 	}
 	return r
 }
@@ -304,7 +304,7 @@ func (c *Client) ExpectModuleEvent(t *testing.T) *dap.ModuleEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ModuleEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ModuleEvent", m)
+		t.Fatalf("got %#v, want *dap.ModuleEvent", m)
 	}
 	return r
 }
@@ -316,7 +316,7 @@ func (c *Client) ExpectModulesResponse(t *testing.T) *dap.ModulesResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ModulesResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ModulesResponse", m)
+		t.Fatalf("got %#v, want *dap.ModulesResponse", m)
 	}
 	return r
 }
@@ -328,7 +328,7 @@ func (c *Client) ExpectNextResponse(t *testing.T) *dap.NextResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.NextResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.NextResponse", m)
+		t.Fatalf("got %#v, want *dap.NextResponse", m)
 	}
 	return r
 }
@@ -340,7 +340,7 @@ func (c *Client) ExpectOutputEvent(t *testing.T) *dap.OutputEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.OutputEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.OutputEvent", m)
+		t.Fatalf("got %#v, want *dap.OutputEvent", m)
 	}
 	return r
 }
@@ -352,7 +352,7 @@ func (c *Client) ExpectPauseResponse(t *testing.T) *dap.PauseResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.PauseResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.PauseResponse", m)
+		t.Fatalf("got %#v, want *dap.PauseResponse", m)
 	}
 	return r
 }
@@ -364,7 +364,7 @@ func (c *Client) ExpectProcessEvent(t *testing.T) *dap.ProcessEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ProcessEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ProcessEvent", m)
+		t.Fatalf("got %#v, want *dap.ProcessEvent", m)
 	}
 	return r
 }
@@ -376,7 +376,7 @@ func (c *Client) ExpectProgressEndEvent(t *testing.T) *dap.ProgressEndEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ProgressEndEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ProgressEndEvent", m)
+		t.Fatalf("got %#v, want *dap.ProgressEndEvent", m)
 	}
 	return r
 }
@@ -388,7 +388,7 @@ func (c *Client) ExpectProgressStartEvent(t *testing.T) *dap.ProgressStartEvent
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ProgressStartEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ProgressStartEvent", m)
+		t.Fatalf("got %#v, want *dap.ProgressStartEvent", m)
 	}
 	return r
 }
@@ -400,7 +400,7 @@ func (c *Client) ExpectProgressUpdateEvent(t *testing.T) *dap.ProgressUpdateEven
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ProgressUpdateEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ProgressUpdateEvent", m)
+		t.Fatalf("got %#v, want *dap.ProgressUpdateEvent", m)
 	}
 	return r
 }
@@ -412,7 +412,7 @@ func (c *Client) ExpectReadMemoryResponse(t *testing.T) *dap.ReadMemoryResponse
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ReadMemoryResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ReadMemoryResponse", m)
+		t.Fatalf("got %#v, want *dap.ReadMemoryResponse", m)
 	}
 	return r
 }
@@ -424,7 +424,7 @@ func (c *Client) ExpectRestartFrameResponse(t *testing.T) *dap.RestartFrameRespo
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.RestartFrameResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.RestartFrameResponse", m)
+		t.Fatalf("got %#v, want *dap.RestartFrameResponse", m)
 	}
 	return r
 }
@@ -436,7 +436,7 @@ func (c *Client) ExpectRestartResponse(t *testing.T) *dap.RestartResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.RestartResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.RestartResponse", m)
+		t.Fatalf("got %#v, want *dap.RestartResponse", m)
 	}
 	return r
 }
@@ -448,7 +448,7 @@ func (c *Client) ExpectReverseContinueResponse(t *testing.T) *dap.ReverseContinu
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ReverseContinueResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ReverseContinueResponse", m)
+		t.Fatalf("got %#v, want *dap.ReverseContinueResponse", m)
 	}
 	return r
 }
@@ -460,7 +460,7 @@ func (c *Client) ExpectRunInTerminalResponse(t *testing.T) *dap.RunInTerminalRes
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.RunInTerminalResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.RunInTerminalResponse", m)
+		t.Fatalf("got %#v, want *dap.RunInTerminalResponse", m)
 	}
 	return r
 }
@@ -472,7 +472,7 @@ func (c *Client) ExpectScopesResponse(t *testing.T) *dap.ScopesResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ScopesResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ScopesResponse", m)
+		t.Fatalf("got %#v, want *dap.ScopesResponse", m)
 	}
 	return r
 }
@@ -484,7 +484,7 @@ func (c *Client) ExpectSetBreakpointsResponse(t *testing.T) *dap.SetBreakpointsR
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.SetBreakpointsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.SetBreakpointsResponse", m)
+		t.Fatalf("got %#v, want *dap.SetBreakpointsResponse", m)
 	}
 	return r
 }
@@ -496,7 +496,7 @@ func (c *Client) ExpectSetDataBreakpointsResponse(t *testing.T) *dap.SetDataBrea
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.SetDataBreakpointsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.SetDataBreakpointsResponse", m)
+		t.Fatalf("got %#v, want *dap.SetDataBreakpointsResponse", m)
 	}
 	return r
 }
@@ -508,7 +508,7 @@ func (c *Client) ExpectSetExceptionBreakpointsResponse(t *testing.T) *dap.SetExc
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.SetExceptionBreakpointsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.SetExceptionBreakpointsResponse", m)
+		t.Fatalf("got %#v, want *dap.SetExceptionBreakpointsResponse", m)
 	}
 	return r
 }
@@ -520,7 +520,7 @@ func (c *Client) ExpectSetExpressionResponse(t *testing.T) *dap.SetExpressionRes
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.SetExpressionResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.SetExpressionResponse", m)
+		t.Fatalf("got %#v, want *dap.SetExpressionResponse", m)
 	}
 	return r
 }
@@ -532,7 +532,7 @@ func (c *Client) ExpectSetFunctionBreakpointsResponse(t *testing.T) *dap.SetFunc
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.SetFunctionBreakpointsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.SetFunctionBreakpointsResponse", m)
+		t.Fatalf("got %#v, want *dap.SetFunctionBreakpointsResponse", m)
 	}
 	return r
 }
@@ -544,7 +544,7 @@ func (c *Client) ExpectSetInstructionBreakpointsResponse(t *testing.T) *dap.SetI
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.SetInstructionBreakpointsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.SetInstructionBreakpointsResponse", m)
+		t.Fatalf("got %#v, want *dap.SetInstructionBreakpointsResponse", m)
 	}
 	return r
 }
@@ -556,7 +556,7 @@ func (c *Client) ExpectSetVariableResponse(t *testing.T) *dap.SetVariableRespons
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.SetVariableResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.SetVariableResponse", m)
+		t.Fatalf("got %#v, want *dap.SetVariableResponse", m)
 	}
 	return r
 }
@@ -568,7 +568,7 @@ func (c *Client) ExpectSourceResponse(t *testing.T) *dap.SourceResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.SourceResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.SourceResponse", m)
+		t.Fatalf("got %#v, want *dap.SourceResponse", m)
 	}
 	return r
 }
@@ -580,7 +580,7 @@ func (c *Client) ExpectStackTraceResponse(t *testing.T) *dap.StackTraceResponse
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.StackTraceResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.StackTraceResponse", m)
+		t.Fatalf("got %#v, want *dap.StackTraceResponse", m)
 	}
 	return r
 }
@@ -592,7 +592,7 @@ func (c *Client) ExpectStepBackResponse(t *testing.T) *dap.StepBackResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.StepBackResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.StepBackResponse", m)
+		t.Fatalf("got %#v, want *dap.StepBackResponse", m)
 	}
 	return r
 }
@@ -604,7 +604,7 @@ func (c *Client) ExpectStepInResponse(t *testing.T) *dap.StepInResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.StepInResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.StepInResponse", m)
+		t.Fatalf("got %#v, want *dap.StepInResponse", m)
 	}
 	return r
 }
@@ -616,7 +616,7 @@ func (c *Client) ExpectStepInTargetsResponse(t *testing.T) *dap.StepInTargetsRes
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.StepInTargetsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.StepInTargetsResponse", m)
+		t.Fatalf("got %#v, want *dap.StepInTargetsResponse", m)
 	}
 	return r
 }
@@ -628,7 +628,7 @@ func (c *Client) ExpectStepOutResponse(t *testing.T) *dap.StepOutResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.StepOutResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.StepOutResponse", m)
+		t.Fatalf("got %#v, want *dap.StepOutResponse", m)
 	}
 	return r
 }
@@ -640,7 +640,7 @@ func (c *Client) ExpectStoppedEvent(t *testing.T) *dap.StoppedEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.StoppedEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.StoppedEvent", m)
+		t.Fatalf("got %#v, want *dap.StoppedEvent", m)
 	}
 	return r
 }
@@ -652,7 +652,7 @@ func (c *Client) ExpectTerminateResponse(t *testing.T) *dap.TerminateResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.TerminateResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.TerminateResponse", m)
+		t.Fatalf("got %#v, want *dap.TerminateResponse", m)
 	}
 	return r
 }
@@ -664,7 +664,7 @@ func (c *Client) ExpectTerminateThreadsResponse(t *testing.T) *dap.TerminateThre
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.TerminateThreadsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.TerminateThreadsResponse", m)
+		t.Fatalf("got %#v, want *dap.TerminateThreadsResponse", m)
 	}
 	return r
 }
@@ -676,7 +676,7 @@ func (c *Client) ExpectTerminatedEvent(t *testing.T) *dap.TerminatedEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.TerminatedEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.TerminatedEvent", m)
+		t.Fatalf("got %#v, want *dap.TerminatedEvent", m)
 	}
 	return r
 }
@@ -688,7 +688,7 @@ func (c *Client) ExpectThreadEvent(t *testing.T) *dap.ThreadEvent {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ThreadEvent)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ThreadEvent", m)
+		t.Fatalf("got %#v, want *dap.ThreadEvent", m)
 	}
 	return r
 }
@@ -700,7 +700,7 @@ func (c *Client) ExpectThreadsResponse(t *testing.T) *dap.ThreadsResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.ThreadsResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.ThreadsResponse", m)
+		t.Fatalf("got %#v, want *dap.ThreadsResponse", m)
 	}
 	return r
 }
@@ -712,7 +712,7 @@ func (c *Client) ExpectVariablesResponse(t *testing.T) *dap.VariablesResponse {
 	m := c.ExpectMessage(t)
 	r, ok := m.(*dap.VariablesResponse)
 	if !ok {
-		t.Fatalf("got %q, want *dap.VariablesResponse", m)
+		t.Fatalf("got %#v, want *dap.VariablesResponse", m)
 	}
 	return r
 }
diff --git a/service/dap/server_test.go b/service/dap/server_test.go
index ff1d9f10..5dcf11c9 100644
--- a/service/dap/server_test.go
+++ b/service/dap/server_test.go
@@ -437,9 +437,9 @@ func TestContinueOnEntry(t *testing.T) {
 				}
 				// Single current thread is sent when the program is running
 				// because DAP spec expects at least one thread.
-				// TODO(polina): accept empty already-terminated response here as well?
-				if len(m.Body.Threads) != 1 || m.Body.Threads[0].Id != -1 || m.Body.Threads[0].Name != "Current" {
-					t.Errorf("\ngot  %#v\nwant Id=-1, Name=\"Current\"", m.Body.Threads)
+				// Also accept empty already-terminated response.
+				if len(m.Body.Threads) != 0 && (len(m.Body.Threads) != 1 || m.Body.Threads[0].Id != -1 || m.Body.Threads[0].Name != "Current") {
+					t.Errorf("\ngot  %#v\nwant Id=-1, Name=\"Current\" or empty", m.Body.Threads)
 				}
 			case *dap.TerminatedEvent:
 			default:
@@ -502,8 +502,12 @@ func TestPreSetBreakpoint(t *testing.T) {
 			msg := client.ExpectMessage(t)
 			switch m := msg.(type) {
 			case *dap.ThreadsResponse:
-				if len(m.Body.Threads) != 1 || m.Body.Threads[0].Id != -1 || m.Body.Threads[0].Name != "Current" {
-					t.Errorf("\ngot  %#v\nwant Id=-1, Name=\"Current\"", m.Body.Threads)
+				// If the thread request arrived while the program was running, we expect to get the dummy response
+				// with a single goroutine "Current".
+				// If the thread request arrived after the stop, we should get the goroutine stopped at main.Increment.
+				if (len(m.Body.Threads) != 1 || m.Body.Threads[0].Id != -1 || m.Body.Threads[0].Name != "Current") &&
+					(len(m.Body.Threads) < 1 || m.Body.Threads[0].Id != 1 || !strings.HasPrefix(m.Body.Threads[0].Name, "* [Go 1] main.Increment")) {
+					t.Errorf("\ngot  %#v\nwant Id=-1, Name=\"Current\" or Id=1, Name=\"* [Go 1] main.Increment ...\"", m.Body.Threads)
 				}
 			case *dap.StoppedEvent:
 				if m.Body.Reason != "breakpoint" || m.Body.ThreadId != 1 || !m.Body.AllThreadsStopped {
@@ -567,8 +571,8 @@ func TestPreSetBreakpoint(t *testing.T) {
 		client.VariablesRequest(1000) // Arguments
 		args := client.ExpectVariablesResponse(t)
 		expectChildren(t, args, "Arguments", 2)
-		expectVarExact(t, args, 0, "y", "y", "0", noChildren)
-		expectVarExact(t, args, 1, "~r1", "", "0", noChildren)
+		expectVarExact(t, args, 0, "y", "y", "0", "uint", noChildren)
+		expectVarExact(t, args, 1, "~r1", "", "0", "uint", noChildren)
 
 		client.VariablesRequest(1001) // Locals
 		locals := client.ExpectVariablesResponse(t)
@@ -662,7 +666,7 @@ func expectChildren(t *testing.T, got *dap.VariablesResponse, parentName string,
 //     useExactMatch - true if name, evalName and value are to be compared to exactly, false if to be used as regex
 //     hasRef - true if the variable should have children and therefore a non-0 variable reference
 //     ref - reference to retrieve children of this variable (0 if none)
-func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value string, useExactMatch, hasRef bool) (ref int) {
+func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value, typ string, useExactMatch, hasRef bool) (ref int) {
 	t.Helper()
 	if len(got.Body.Variables) <= i {
 		t.Errorf("\ngot  len=%d (children=%#v)\nwant len>%d", len(got.Body.Variables), got.Body.Variables, i)
@@ -709,19 +713,28 @@ func expectVar(t *testing.T, got *dap.VariablesResponse, i int, name, evalName,
 	if !matchedValue {
 		t.Errorf("\ngot  %s=%q\nwant %q", name, goti.Value, value)
 	}
+	matchedType := false
+	if useExactMatch {
+		matchedType = (goti.Type == typ)
+	} else {
+		matchedType, _ = regexp.MatchString(typ, goti.Type)
+	}
+	if !matchedType {
+		t.Errorf("\ngot  %s=%q\nwant %q", name, goti.Type, typ)
+	}
 	return goti.VariablesReference
 }
 
 // expectVarExact is a helper like expectVar that matches value exactly.
-func expectVarExact(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value string, hasRef bool) (ref int) {
+func expectVarExact(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value, typ string, hasRef bool) (ref int) {
 	t.Helper()
-	return expectVar(t, got, i, name, evalName, value, true, hasRef)
+	return expectVar(t, got, i, name, evalName, value, typ, true, hasRef)
 }
 
 // expectVarRegex is a helper like expectVar that treats value, evalName or name as a regex.
-func expectVarRegex(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value string, hasRef bool) (ref int) {
+func expectVarRegex(t *testing.T, got *dap.VariablesResponse, i int, name, evalName, value, typ string, hasRef bool) (ref int) {
 	t.Helper()
-	return expectVar(t, got, i, name, evalName, value, false, hasRef)
+	return expectVar(t, got, i, name, evalName, value, typ, false, hasRef)
 }
 
 // validateEvaluateName issues an evaluate request with evaluateName of a variable and
@@ -854,14 +867,14 @@ func TestScopesAndVariablesRequests(t *testing.T) {
 					client.VariablesRequest(1000)
 					args := client.ExpectVariablesResponse(t)
 					expectChildren(t, args, "Arguments", 2)
-					expectVarExact(t, args, 0, "baz", "baz", `"bazburzum"`, noChildren)
-					ref := expectVarExact(t, args, 1, "bar", "bar", `main.FooBar {Baz: 10, Bur: "lorem"}`, hasChildren)
+					expectVarExact(t, args, 0, "baz", "baz", `"bazburzum"`, "string", noChildren)
+					ref := expectVarExact(t, args, 1, "bar", "bar", `main.FooBar {Baz: 10, Bur: "lorem"}`, "main.FooBar", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						bar := client.ExpectVariablesResponse(t)
 						expectChildren(t, bar, "bar", 2)
-						expectVarExact(t, bar, 0, "Baz", "bar.Baz", "10", noChildren)
-						expectVarExact(t, bar, 1, "Bur", "bar.Bur", `"lorem"`, noChildren)
+						expectVarExact(t, bar, 0, "Baz", "bar.Baz", "10", "int", noChildren)
+						expectVarExact(t, bar, 1, "Bur", "bar.Bur", `"lorem"`, "string", noChildren)
 						validateEvaluateName(t, client, bar, 0)
 						validateEvaluateName(t, client, bar, 1)
 					}
@@ -870,7 +883,7 @@ func TestScopesAndVariablesRequests(t *testing.T) {
 
 					client.VariablesRequest(1002)
 					globals := client.ExpectVariablesResponse(t)
-					expectVarExact(t, globals, 0, "p1", "main.p1", "10", noChildren)
+					expectVarExact(t, globals, 0, "p1", "main.p1", "10", "int", noChildren)
 
 					// Locals
 
@@ -879,75 +892,75 @@ func TestScopesAndVariablesRequests(t *testing.T) {
 					expectChildren(t, locals, "Locals", 31)
 
 					// reflect.Kind == Bool
-					expectVarExact(t, locals, -1, "b1", "b1", "true", noChildren)
-					expectVarExact(t, locals, -1, "b2", "b2", "false", noChildren)
+					expectVarExact(t, locals, -1, "b1", "b1", "true", "bool", noChildren)
+					expectVarExact(t, locals, -1, "b2", "b2", "false", "bool", noChildren)
 					// reflect.Kind == Int
-					expectVarExact(t, locals, -1, "a2", "a2", "6", noChildren)
-					expectVarExact(t, locals, -1, "neg", "neg", "-1", noChildren)
+					expectVarExact(t, locals, -1, "a2", "a2", "6", "int", noChildren)
+					expectVarExact(t, locals, -1, "neg", "neg", "-1", "int", noChildren)
 					// reflect.Kind == Int8
-					expectVarExact(t, locals, -1, "i8", "i8", "1", noChildren)
+					expectVarExact(t, locals, -1, "i8", "i8", "1", "int8", noChildren)
 					// reflect.Kind == Int16 - see testvariables2
 					// reflect.Kind == Int32 - see testvariables2
 					// reflect.Kind == Int64 - see testvariables2
 					// reflect.Kind == Uint
 					// reflect.Kind == Uint8
-					expectVarExact(t, locals, -1, "u8", "u8", "255", noChildren)
+					expectVarExact(t, locals, -1, "u8", "u8", "255", "uint8", noChildren)
 					// reflect.Kind == Uint16
-					expectVarExact(t, locals, -1, "u16", "u16", "65535", noChildren)
+					expectVarExact(t, locals, -1, "u16", "u16", "65535", "uint16", noChildren)
 					// reflect.Kind == Uint32
-					expectVarExact(t, locals, -1, "u32", "u32", "4294967295", noChildren)
+					expectVarExact(t, locals, -1, "u32", "u32", "4294967295", "uint32", noChildren)
 					// reflect.Kind == Uint64
-					expectVarExact(t, locals, -1, "u64", "u64", "18446744073709551615", noChildren)
+					expectVarExact(t, locals, -1, "u64", "u64", "18446744073709551615", "uint64", noChildren)
 					// reflect.Kind == Uintptr
-					expectVarExact(t, locals, -1, "up", "up", "5", noChildren)
+					expectVarExact(t, locals, -1, "up", "up", "5", "uintptr", noChildren)
 					// reflect.Kind == Float32
-					expectVarExact(t, locals, -1, "f32", "f32", "1.2", noChildren)
+					expectVarExact(t, locals, -1, "f32", "f32", "1.2", "float32", noChildren)
 					// reflect.Kind == Float64
-					expectVarExact(t, locals, -1, "a3", "a3", "7.23", noChildren)
+					expectVarExact(t, locals, -1, "a3", "a3", "7.23", "float64", noChildren)
 					// reflect.Kind == Complex64
-					ref = expectVarExact(t, locals, -1, "c64", "c64", "(1 + 2i)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "c64", "c64", "(1 + 2i)", "complex64", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						c64 := client.ExpectVariablesResponse(t)
 						expectChildren(t, c64, "c64", 2)
-						expectVarExact(t, c64, 0, "real", "", "1", noChildren)
-						expectVarExact(t, c64, 1, "imaginary", "", "2", noChildren)
+						expectVarExact(t, c64, 0, "real", "", "1", "float32", noChildren)
+						expectVarExact(t, c64, 1, "imaginary", "", "2", "float32", noChildren)
 					}
 					// reflect.Kind == Complex128
-					ref = expectVarExact(t, locals, -1, "c128", "c128", "(2 + 3i)", hasChildren)
+					ref = expectVarExact(t, locals, -1, "c128", "c128", "(2 + 3i)", "complex128", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						c128 := client.ExpectVariablesResponse(t)
 						expectChildren(t, c128, "c128", 2)
-						expectVarExact(t, c128, 0, "real", "", "2", noChildren)
-						expectVarExact(t, c128, 1, "imaginary", "", "3", noChildren)
+						expectVarExact(t, c128, 0, "real", "", "2", "float64", noChildren)
+						expectVarExact(t, c128, 1, "imaginary", "", "3", "float64", noChildren)
 					}
 					// reflect.Kind == Array
-					ref = expectVarExact(t, locals, -1, "a4", "a4", "[2]int [1,2]", hasChildren)
+					ref = expectVarExact(t, locals, -1, "a4", "a4", "[2]int [1,2]", "[2]int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a4 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a4, "a4", 2)
-						expectVarExact(t, a4, 0, "[0]", "a4[0]", "1", noChildren)
-						expectVarExact(t, a4, 1, "[1]", "a4[1]", "2", noChildren)
+						expectVarExact(t, a4, 0, "[0]", "a4[0]", "1", "int", noChildren)
+						expectVarExact(t, a4, 1, "[1]", "a4[1]", "2", "int", noChildren)
 					}
-					ref = expectVarExact(t, locals, -1, "a11", "a11", `[3]main.FooBar [{Baz: 1, Bur: "a"},{Baz: 2, Bur: "b"},{Baz: 3, Bur: "c"}]`, hasChildren)
+					ref = expectVarExact(t, locals, -1, "a11", "a11", `[3]main.FooBar [{Baz: 1, Bur: "a"},{Baz: 2, Bur: "b"},{Baz: 3, Bur: "c"}]`, "[3]main.FooBar", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a11 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a11, "a11", 3)
-						expectVarExact(t, a11, 0, "[0]", "a11[0]", `main.FooBar {Baz: 1, Bur: "a"}`, hasChildren)
-						ref = expectVarExact(t, a11, 1, "[1]", "a11[1]", `main.FooBar {Baz: 2, Bur: "b"}`, hasChildren)
+						expectVarExact(t, a11, 0, "[0]", "a11[0]", `main.FooBar {Baz: 1, Bur: "a"}`, "main.FooBar", hasChildren)
+						ref = expectVarExact(t, a11, 1, "[1]", "a11[1]", `main.FooBar {Baz: 2, Bur: "b"}`, "main.FooBar", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							a11_1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, a11_1, "a11[1]", 2)
-							expectVarExact(t, a11_1, 0, "Baz", "a11[1].Baz", "2", noChildren)
-							expectVarExact(t, a11_1, 1, "Bur", "a11[1].Bur", `"b"`, noChildren)
+							expectVarExact(t, a11_1, 0, "Baz", "a11[1].Baz", "2", "int", noChildren)
+							expectVarExact(t, a11_1, 1, "Bur", "a11[1].Bur", `"b"`, "string", noChildren)
 							validateEvaluateName(t, client, a11_1, 0)
 							validateEvaluateName(t, client, a11_1, 1)
 						}
-						expectVarExact(t, a11, 2, "[2]", "a11[2]", `main.FooBar {Baz: 3, Bur: "c"}`, hasChildren)
+						expectVarExact(t, a11, 2, "[2]", "a11[2]", `main.FooBar {Baz: 3, Bur: "c"}`, "main.FooBar", hasChildren)
 					}
 
 					// reflect.Kind == Chan - see testvariables2
@@ -955,96 +968,96 @@ func TestScopesAndVariablesRequests(t *testing.T) {
 					// reflect.Kind == Interface - see testvariables2
 					// reflect.Kind == Map - see testvariables2
 					// reflect.Kind == Ptr
-					ref = expectVarExact(t, locals, -1, "a7", "a7", `*main.FooBar {Baz: 5, Bur: "strum"}`, hasChildren)
+					ref = expectVarExact(t, locals, -1, "a7", "a7", `*main.FooBar {Baz: 5, Bur: "strum"}`, "*main.FooBar", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a7 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a7, "a7", 1)
-						ref = expectVarExact(t, a7, 0, "", "(*a7)", `main.FooBar {Baz: 5, Bur: "strum"}`, hasChildren)
+						ref = expectVarExact(t, a7, 0, "", "(*a7)", `main.FooBar {Baz: 5, Bur: "strum"}`, "main.FooBar", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							a7val := client.ExpectVariablesResponse(t)
 							expectChildren(t, a7val, "*a7", 2)
-							expectVarExact(t, a7val, 0, "Baz", "(*a7).Baz", "5", noChildren)
-							expectVarExact(t, a7val, 1, "Bur", "(*a7).Bur", `"strum"`, noChildren)
+							expectVarExact(t, a7val, 0, "Baz", "(*a7).Baz", "5", "int", noChildren)
+							expectVarExact(t, a7val, 1, "Bur", "(*a7).Bur", `"strum"`, "string", noChildren)
 							validateEvaluateName(t, client, a7val, 0)
 							validateEvaluateName(t, client, a7val, 1)
 						}
 					}
 					// TODO(polina): how to test for "nil" (without type) and "void"?
-					expectVarExact(t, locals, -1, "a9", "a9", "*main.FooBar nil", noChildren)
+					expectVarExact(t, locals, -1, "a9", "a9", "*main.FooBar nil", "*main.FooBar", noChildren)
 					// reflect.Kind == Slice
-					ref = expectVarExact(t, locals, -1, "a5", "a5", "[]int len: 5, cap: 5, [1,2,3,4,5]", hasChildren)
+					ref = expectVarExact(t, locals, -1, "a5", "a5", "[]int len: 5, cap: 5, [1,2,3,4,5]", "[]int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a5 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a5, "a5", 5)
-						expectVarExact(t, a5, 0, "[0]", "a5[0]", "1", noChildren)
-						expectVarExact(t, a5, 4, "[4]", "a5[4]", "5", noChildren)
+						expectVarExact(t, a5, 0, "[0]", "a5[0]", "1", "int", noChildren)
+						expectVarExact(t, a5, 4, "[4]", "a5[4]", "5", "int", noChildren)
 						validateEvaluateName(t, client, a5, 0)
 						validateEvaluateName(t, client, a5, 1)
 					}
-					ref = expectVarExact(t, locals, -1, "a12", "a12", `[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: "d"},{Baz: 5, Bur: "e"}]`, hasChildren)
+					ref = expectVarExact(t, locals, -1, "a12", "a12", `[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: "d"},{Baz: 5, Bur: "e"}]`, "[]main.FooBar", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a12 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a12, "a12", 2)
-						expectVarExact(t, a12, 0, "[0]", "a12[0]", `main.FooBar {Baz: 4, Bur: "d"}`, hasChildren)
-						ref = expectVarExact(t, a12, 1, "[1]", "a12[1]", `main.FooBar {Baz: 5, Bur: "e"}`, hasChildren)
+						expectVarExact(t, a12, 0, "[0]", "a12[0]", `main.FooBar {Baz: 4, Bur: "d"}`, "main.FooBar", hasChildren)
+						ref = expectVarExact(t, a12, 1, "[1]", "a12[1]", `main.FooBar {Baz: 5, Bur: "e"}`, "main.FooBar", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							a12_1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, a12_1, "a12[1]", 2)
-							expectVarExact(t, a12_1, 0, "Baz", "a12[1].Baz", "5", noChildren)
-							expectVarExact(t, a12_1, 1, "Bur", "a12[1].Bur", `"e"`, noChildren)
+							expectVarExact(t, a12_1, 0, "Baz", "a12[1].Baz", "5", "int", noChildren)
+							expectVarExact(t, a12_1, 1, "Bur", "a12[1].Bur", `"e"`, "string", noChildren)
 							validateEvaluateName(t, client, a12_1, 0)
 							validateEvaluateName(t, client, a12_1, 1)
 						}
 					}
-					ref = expectVarExact(t, locals, -1, "a13", "a13", `[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: "f"},*{Baz: 7, Bur: "g"},*{Baz: 8, Bur: "h"}]`, hasChildren)
+					ref = expectVarExact(t, locals, -1, "a13", "a13", `[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: "f"},*{Baz: 7, Bur: "g"},*{Baz: 8, Bur: "h"}]`, "[]*main.FooBar", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a13 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a13, "a13", 3)
-						expectVarExact(t, a13, 0, "[0]", "a13[0]", `*main.FooBar {Baz: 6, Bur: "f"}`, hasChildren)
-						expectVarExact(t, a13, 1, "[1]", "a13[1]", `*main.FooBar {Baz: 7, Bur: "g"}`, hasChildren)
-						ref = expectVarExact(t, a13, 2, "[2]", "a13[2]", `*main.FooBar {Baz: 8, Bur: "h"}`, hasChildren)
+						expectVarExact(t, a13, 0, "[0]", "a13[0]", `*main.FooBar {Baz: 6, Bur: "f"}`, "*main.FooBar", hasChildren)
+						expectVarExact(t, a13, 1, "[1]", "a13[1]", `*main.FooBar {Baz: 7, Bur: "g"}`, "*main.FooBar", hasChildren)
+						ref = expectVarExact(t, a13, 2, "[2]", "a13[2]", `*main.FooBar {Baz: 8, Bur: "h"}`, "*main.FooBar", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							a13_2 := client.ExpectVariablesResponse(t)
 							expectChildren(t, a13_2, "a13[2]", 1)
-							ref = expectVarExact(t, a13_2, 0, "", "(*a13[2])", `main.FooBar {Baz: 8, Bur: "h"}`, hasChildren)
+							ref = expectVarExact(t, a13_2, 0, "", "(*a13[2])", `main.FooBar {Baz: 8, Bur: "h"}`, "main.FooBar", hasChildren)
 							validateEvaluateName(t, client, a13_2, 0)
 							if ref > 0 {
 								client.VariablesRequest(ref)
 								val := client.ExpectVariablesResponse(t)
 								expectChildren(t, val, "*a13[2]", 2)
-								expectVarExact(t, val, 0, "Baz", "(*a13[2]).Baz", "8", noChildren)
-								expectVarExact(t, val, 1, "Bur", "(*a13[2]).Bur", `"h"`, noChildren)
+								expectVarExact(t, val, 0, "Baz", "(*a13[2]).Baz", "8", "int", noChildren)
+								expectVarExact(t, val, 1, "Bur", "(*a13[2]).Bur", `"h"`, "string", noChildren)
 								validateEvaluateName(t, client, val, 0)
 								validateEvaluateName(t, client, val, 1)
 							}
 						}
 					}
 					// reflect.Kind == String
-					expectVarExact(t, locals, -1, "a1", "a1", `"foofoofoofoofoofoo"`, noChildren)
-					expectVarExact(t, locals, -1, "a10", "a10", `"ofo"`, noChildren)
+					expectVarExact(t, locals, -1, "a1", "a1", `"foofoofoofoofoofoo"`, "string", noChildren)
+					expectVarExact(t, locals, -1, "a10", "a10", `"ofo"`, "string", noChildren)
 					// reflect.Kind == Struct
-					ref = expectVarExact(t, locals, -1, "a6", "a6", `main.FooBar {Baz: 8, Bur: "word"}`, hasChildren)
+					ref = expectVarExact(t, locals, -1, "a6", "a6", `main.FooBar {Baz: 8, Bur: "word"}`, "main.FooBar", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a6 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a6, "a6", 2)
-						expectVarExact(t, a6, 0, "Baz", "a6.Baz", "8", noChildren)
-						expectVarExact(t, a6, 1, "Bur", "a6.Bur", `"word"`, noChildren)
+						expectVarExact(t, a6, 0, "Baz", "a6.Baz", "8", "int", noChildren)
+						expectVarExact(t, a6, 1, "Bur", "a6.Bur", `"word"`, "string", noChildren)
 					}
-					ref = expectVarExact(t, locals, -1, "a8", "a8", `main.FooBar2 {Bur: 10, Baz: "feh"}`, hasChildren)
+					ref = expectVarExact(t, locals, -1, "a8", "a8", `main.FooBar2 {Bur: 10, Baz: "feh"}`, "main.FooBar2", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						a8 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a8, "a8", 2)
-						expectVarExact(t, a8, 0, "Bur", "a8.Bur", "10", noChildren)
-						expectVarExact(t, a8, 1, "Baz", "a8.Baz", `"feh"`, noChildren)
+						expectVarExact(t, a8, 0, "Bur", "a8.Bur", "10", "int", noChildren)
+						expectVarExact(t, a8, 1, "Baz", "a8.Baz", `"feh"`, "string", noChildren)
 					}
 					// reflect.Kind == UnsafePointer - see testvariables2
 				},
@@ -1076,11 +1089,11 @@ func TestScopesAndVariablesRequests(t *testing.T) {
 					client.VariablesRequest(1001) // Locals
 					locals := client.ExpectVariablesResponse(t)
 					expectChildren(t, locals, "Locals", 1)
-					expectVarExact(t, locals, -1, "a1", "a1", `"bur"`, noChildren)
+					expectVarExact(t, locals, -1, "a1", "a1", `"bur"`, "string", noChildren)
 
 					client.VariablesRequest(1002) // Globals
 					globals := client.ExpectVariablesResponse(t)
-					expectVarExact(t, globals, 0, "p1", "main.p1", "10", noChildren)
+					expectVarExact(t, globals, 0, "p1", "main.p1", "10", "int", noChildren)
 
 					client.VariablesRequest(7777)
 					erres = client.ExpectInvisibleErrorResponse(t)
@@ -1144,13 +1157,13 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
 					// reflect.Kind == Bool - see testvariables
 					// reflect.Kind == Int - see testvariables
 					// reflect.Kind == Int8
-					expectVarExact(t, locals, -1, "ni8", "ni8", "-5", noChildren)
+					expectVarExact(t, locals, -1, "ni8", "ni8", "-5", "int8", noChildren)
 					// reflect.Kind == Int16
-					expectVarExact(t, locals, -1, "ni16", "ni16", "-5", noChildren)
+					expectVarExact(t, locals, -1, "ni16", "ni16", "-5", "int16", noChildren)
 					// reflect.Kind == Int32
-					expectVarExact(t, locals, -1, "ni32", "ni32", "-5", noChildren)
+					expectVarExact(t, locals, -1, "ni32", "ni32", "-5", "int32", noChildren)
 					// reflect.Kind == Int64
-					expectVarExact(t, locals, -1, "ni64", "ni64", "-5", noChildren)
+					expectVarExact(t, locals, -1, "ni64", "ni64", "-5", "int64", noChildren)
 					// reflect.Kind == Uint
 					// reflect.Kind == Uint8 - see testvariables
 					// reflect.Kind == Uint16 - see testvariables
@@ -1159,209 +1172,209 @@ func TestScopesAndVariablesRequests2(t *testing.T) {
 					// reflect.Kind == Uintptr - see testvariables
 					// reflect.Kind == Float32 - see testvariables
 					// reflect.Kind == Float64
-					expectVarExact(t, locals, -1, "pinf", "pinf", "+Inf", noChildren)
-					expectVarExact(t, locals, -1, "ninf", "ninf", "-Inf", noChildren)
-					expectVarExact(t, locals, -1, "nan", "nan", "NaN", noChildren)
+					expectVarExact(t, locals, -1, "pinf", "pinf", "+Inf", "float64", noChildren)
+					expectVarExact(t, locals, -1, "ninf", "ninf", "-Inf", "float64", noChildren)
+					expectVarExact(t, locals, -1, "nan", "nan", "NaN", "float64", noChildren)
 					// reflect.Kind == Complex64 - see testvariables
 					// reflect.Kind == Complex128 - see testvariables
 					// reflect.Kind == Array
-					expectVarExact(t, locals, -1, "a0", "a0", "[0]int []", noChildren)
+					expectVarExact(t, locals, -1, "a0", "a0", "[0]int []", "[0]int", noChildren)
 					// reflect.Kind == Chan
-					ref := expectVarExact(t, locals, -1, "ch1", "ch1", "chan int 4/11", hasChildren)
+					ref := expectVarExact(t, locals, -1, "ch1", "ch1", "chan int 4/11", "chan int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						ch1 := client.ExpectVariablesResponse(t)
 						expectChildren(t, ch1, "ch1", 11)
-						expectVarExact(t, ch1, 0, "qcount", "ch1.qcount", "4", noChildren)
-						expectVarRegex(t, ch1, 10, "lock", "ch1.lock", `runtime\.mutex {.*key: 0.*}`, hasChildren)
+						expectVarExact(t, ch1, 0, "qcount", "ch1.qcount", "4", "uint", noChildren)
+						expectVarRegex(t, ch1, 10, "lock", "ch1.lock", `runtime\.mutex {.*key: 0.*}`, `runtime\.mutex`, hasChildren)
 						validateEvaluateName(t, client, ch1, 0)
 						validateEvaluateName(t, client, ch1, 10)
 					}
-					expectVarExact(t, locals, -1, "chnil", "chnil", "chan int nil", noChildren)
+					expectVarExact(t, locals, -1, "chnil", "chnil", "chan int nil", "chan int", noChildren)
 					// reflect.Kind == Func
-					expectVarExact(t, locals, -1, "fn1", "fn1", "main.afunc", noChildren)
-					expectVarExact(t, locals, -1, "fn2", "fn2", "nil", noChildren)
+					expectVarExact(t, locals, -1, "fn1", "fn1", "main.afunc", "main.functype", noChildren)
+					expectVarExact(t, locals, -1, "fn2", "fn2", "nil", "main.functype", noChildren)
 					// reflect.Kind == Interface
-					expectVarExact(t, locals, -1, "ifacenil", "ifacenil", "interface {} nil", noChildren)
-					ref = expectVarExact(t, locals, -1, "iface2", "iface2", "interface {}(string) \"test\"", hasChildren)
+					expectVarExact(t, locals, -1, "ifacenil", "ifacenil", "interface {} nil", "interface {}", noChildren)
+					ref = expectVarExact(t, locals, -1, "iface2", "iface2", "interface {}(string) \"test\"", "interface {}", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						iface2 := client.ExpectVariablesResponse(t)
 						expectChildren(t, iface2, "iface2", 1)
-						expectVarExact(t, iface2, 0, "data", "iface2.(data)", `"test"`, noChildren)
+						expectVarExact(t, iface2, 0, "data", "iface2.(data)", `"test"`, "string", noChildren)
 						validateEvaluateName(t, client, iface2, 0)
 					}
-					ref = expectVarExact(t, locals, -1, "iface4", "iface4", "interface {}([]go/constant.Value) [4]", hasChildren)
+					ref = expectVarExact(t, locals, -1, "iface4", "iface4", "interface {}([]go/constant.Value) [4]", "interface {}", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						iface4 := client.ExpectVariablesResponse(t)
 						expectChildren(t, iface4, "iface4", 1)
-						ref = expectVarExact(t, iface4, 0, "data", "iface4.(data)", "[]go/constant.Value len: 1, cap: 1, [4]", hasChildren)
+						ref = expectVarExact(t, iface4, 0, "data", "iface4.(data)", "[]go/constant.Value len: 1, cap: 1, [4]", "[]go/constant.Value", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							iface4data := client.ExpectVariablesResponse(t)
 							expectChildren(t, iface4data, "iface4.data", 1)
-							ref = expectVarExact(t, iface4data, 0, "[0]", "iface4.(data)[0]", "go/constant.Value(go/constant.int64Val) 4", hasChildren)
+							ref = expectVarExact(t, iface4data, 0, "[0]", "iface4.(data)[0]", "go/constant.Value(go/constant.int64Val) 4", "go/constant.Value", hasChildren)
 							if ref > 0 {
 								client.VariablesRequest(ref)
 								iface4data0 := client.ExpectVariablesResponse(t)
 								expectChildren(t, iface4data0, "iface4.data[0]", 1)
-								expectVarExact(t, iface4data0, 0, "data", "iface4.(data)[0].(data)", "4", noChildren)
+								expectVarExact(t, iface4data0, 0, "data", "iface4.(data)[0].(data)", "4", "go/constant.int64Val", noChildren)
 								validateEvaluateName(t, client, iface4data0, 0)
 							}
 						}
 					}
-					expectVarExact(t, locals, -1, "errnil", "errnil", "error nil", noChildren)
-					ref = expectVarExact(t, locals, -1, "err1", "err1", "error(*main.astruct) *{A: 1, B: 2}", hasChildren)
+					expectVarExact(t, locals, -1, "errnil", "errnil", "error nil", "error", noChildren)
+					ref = expectVarExact(t, locals, -1, "err1", "err1", "error(*main.astruct) *{A: 1, B: 2}", "error", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						err1 := client.ExpectVariablesResponse(t)
 						expectChildren(t, err1, "err1", 1)
-						expectVarExact(t, err1, 0, "data", "err1.(data)", "*main.astruct {A: 1, B: 2}", hasChildren)
+						expectVarExact(t, err1, 0, "data", "err1.(data)", "*main.astruct {A: 1, B: 2}", "*main.astruct", hasChildren)
 						validateEvaluateName(t, client, err1, 0)
 					}
-					ref = expectVarExact(t, locals, -1, "ptrinf", "ptrinf", "*interface {}(**interface {}) **...", hasChildren)
+					ref = expectVarExact(t, locals, -1, "ptrinf", "ptrinf", "*interface {}(**interface {}) **...", "*interface {}", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						ptrinf_val := client.ExpectVariablesResponse(t)
 						expectChildren(t, ptrinf_val, "*ptrinf", 1)
-						ref = expectVarExact(t, ptrinf_val, 0, "", "(*ptrinf)", "interface {}(**interface {}) **...", hasChildren)
+						ref = expectVarExact(t, ptrinf_val, 0, "", "(*ptrinf)", "interface {}(**interface {}) **...", "interface {}", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							ptrinf_val_data := client.ExpectVariablesResponse(t)
 							expectChildren(t, ptrinf_val_data, "(*ptrinf).data", 1)
-							expectVarExact(t, ptrinf_val_data, 0, "data", "(*ptrinf).(data)", "**interface {}(**interface {}) ...", hasChildren)
+							expectVarExact(t, ptrinf_val_data, 0, "data", "(*ptrinf).(data)", "**interface {}(**interface {}) ...", "**interface {}", hasChildren)
 							validateEvaluateName(t, client, ptrinf_val_data, 0)
 						}
 					}
 					// reflect.Kind == Map
-					expectVarExact(t, locals, -1, "mnil", "mnil", "map[string]main.astruct nil", noChildren)
+					expectVarExact(t, locals, -1, "mnil", "mnil", "map[string]main.astruct nil", "map[string]main.astruct", noChildren)
 					// key - scalar, value - compound
-					ref = expectVarExact(t, locals, -1, "m2", "m2", "map[int]*main.astruct [1: *{A: 10, B: 11}, ]", hasChildren)
+					ref = expectVarExact(t, locals, -1, "m2", "m2", "map[int]*main.astruct [1: *{A: 10, B: 11}, ]", "map[int]*main.astruct", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m2 := client.ExpectVariablesResponse(t)
 						expectChildren(t, m2, "m2", 1) // each key-value represented by a single child
-						ref = expectVarExact(t, m2, 0, "1", "m2[1]", "*main.astruct {A: 10, B: 11}", hasChildren)
+						ref = expectVarExact(t, m2, 0, "1", "m2[1]", "*main.astruct {A: 10, B: 11}", "int: *main.astruct", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m2kv1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, m2kv1, "m2[1]", 1)
-							ref = expectVarExact(t, m2kv1, 0, "", "(*m2[1])", "main.astruct {A: 10, B: 11}", hasChildren)
+							ref = expectVarExact(t, m2kv1, 0, "", "(*m2[1])", "main.astruct {A: 10, B: 11}", "main.astruct", hasChildren)
 							if ref > 0 {
 								client.VariablesRequest(ref)
 								m2kv1deref := client.ExpectVariablesResponse(t)
 								expectChildren(t, m2kv1deref, "*m2[1]", 2)
-								expectVarExact(t, m2kv1deref, 0, "A", "(*m2[1]).A", "10", noChildren)
-								expectVarExact(t, m2kv1deref, 1, "B", "(*m2[1]).B", "11", noChildren)
+								expectVarExact(t, m2kv1deref, 0, "A", "(*m2[1]).A", "10", "int", noChildren)
+								expectVarExact(t, m2kv1deref, 1, "B", "(*m2[1]).B", "11", "int", noChildren)
 								validateEvaluateName(t, client, m2kv1deref, 0)
 								validateEvaluateName(t, client, m2kv1deref, 1)
 							}
 						}
 					}
 					// key - compound, value - scalar
-					ref = expectVarExact(t, locals, -1, "m3", "m3", "map[main.astruct]int [{A: 1, B: 1}: 42, {A: 2, B: 2}: 43, ]", hasChildren)
+					ref = expectVarExact(t, locals, -1, "m3", "m3", "map[main.astruct]int [{A: 1, B: 1}: 42, {A: 2, B: 2}: 43, ]", "map[main.astruct]int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m3 := client.ExpectVariablesResponse(t)
 						expectChildren(t, m3, "m3", 2) // each key-value represented by a single child
-						ref = expectVarRegex(t, m3, 0, `main\.astruct {A: 1, B: 1}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "42", hasChildren)
+						ref = expectVarRegex(t, m3, 0, `main\.astruct {A: 1, B: 1}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "42", "int", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m3kv0 := client.ExpectVariablesResponse(t)
 							expectChildren(t, m3kv0, "m3[0]", 2)
-							expectVarRegex(t, m3kv0, 0, "A", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "1", noChildren)
+							expectVarRegex(t, m3kv0, 0, "A", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "1", "int", noChildren)
 							validateEvaluateName(t, client, m3kv0, 0)
 						}
-						ref = expectVarRegex(t, m3, 1, `main\.astruct {A: 2, B: 2}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "43", hasChildren)
+						ref = expectVarRegex(t, m3, 1, `main\.astruct {A: 2, B: 2}`, `m3\[\(\*\(\*"main.astruct"\)\(0x[0-9a-f]+\)\)\]`, "43", "", hasChildren)
 						if ref > 0 { // inspect another key from another key-value child
 							client.VariablesRequest(ref)
 							m3kv1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, m3kv1, "m3[1]", 2)
-							expectVarRegex(t, m3kv1, 1, "B", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", noChildren)
+							expectVarRegex(t, m3kv1, 1, "B", `\(*\(*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", "int", noChildren)
 							validateEvaluateName(t, client, m3kv1, 1)
 						}
 					}
 					// key - compound + truncated, value - scalar
-					ref = expectVarExact(t, locals, -1, "m5", "m5", `map[main.C]int [{s: "very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more"}: 1, ]`, hasChildren)
+					ref = expectVarExact(t, locals, -1, "m5", "m5", `map[main.C]int [{s: "very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more"}: 1, ]`, "map[main.C]int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m5 := client.ExpectVariablesResponse(t)
 						expectChildren(t, m5, "m5", 1)
-						expectVarRegex(t, m5, 0, `main\.C {s: "very long string 0123456789a0123456789b0123456789c01\.\.\. @ 0x[0-9a-f]+`, `m5\[\(\*\(\*"main\.C"\)\(0x[0-9a-f]+\)\)\]`, "1", hasChildren)
+						expectVarRegex(t, m5, 0, `main\.C {s: "very long string 0123456789a0123456789b0123456789c01\.\.\. @ 0x[0-9a-f]+`, `m5\[\(\*\(\*"main\.C"\)\(0x[0-9a-f]+\)\)\]`, "1", `int`, hasChildren)
 					}
 					// key - compound, value - compound
-					ref = expectVarExact(t, locals, -1, "m4", "m4", "map[main.astruct]main.astruct [{A: 1, B: 1}: {A: 11, B: 11}, {A: 2, B: 2}: {A: 22, B: 22}, ]", hasChildren)
+					ref = expectVarExact(t, locals, -1, "m4", "m4", "map[main.astruct]main.astruct [{A: 1, B: 1}: {A: 11, B: 11}, {A: 2, B: 2}: {A: 22, B: 22}, ]", "map[main.astruct]main.astruct", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m4 := client.ExpectVariablesResponse(t)
 						expectChildren(t, m4, "m4", 4) // each key and value represented by a child, so double the key-value count
-						expectVarRegex(t, m4, 0, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 1, B: 1}`, hasChildren)
-						expectVarRegex(t, m4, 1, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 11, B: 11}`, hasChildren)
-						ref = expectVarRegex(t, m4, 2, `\[key 1\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 2, B: 2}`, hasChildren)
+						expectVarRegex(t, m4, 0, `\[key 0\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 1, B: 1}`, `main\.astruct`, hasChildren)
+						expectVarRegex(t, m4, 1, `\[val 0\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 11, B: 11}`, `main\.astruct`, hasChildren)
+						ref = expectVarRegex(t, m4, 2, `\[key 1\]`, `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)`, `main\.astruct {A: 2, B: 2}`, `main\.astruct`, hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m4Key1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, m4Key1, "m4Key1", 2)
-							expectVarRegex(t, m4Key1, 0, "A", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "2", noChildren)
-							expectVarRegex(t, m4Key1, 1, "B", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", noChildren)
+							expectVarRegex(t, m4Key1, 0, "A", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.A`, "2", "int", noChildren)
+							expectVarRegex(t, m4Key1, 1, "B", `\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\.B`, "2", "int", noChildren)
 							validateEvaluateName(t, client, m4Key1, 0)
 							validateEvaluateName(t, client, m4Key1, 1)
 						}
-						ref = expectVarRegex(t, m4, 3, `\[val 1\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 22, B: 22}`, hasChildren)
+						ref = expectVarRegex(t, m4, 3, `\[val 1\]`, `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]`, `main\.astruct {A: 22, B: 22}`, "main.astruct", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							m4Val1 := client.ExpectVariablesResponse(t)
 							expectChildren(t, m4Val1, "m4Val1", 2)
-							expectVarRegex(t, m4Val1, 0, "A", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.A`, "22", noChildren)
-							expectVarRegex(t, m4Val1, 1, "B", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.B`, "22", noChildren)
+							expectVarRegex(t, m4Val1, 0, "A", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.A`, "22", "int", noChildren)
+							expectVarRegex(t, m4Val1, 1, "B", `m4\[\(\*\(\*"main\.astruct"\)\(0x[0-9a-f]+\)\)\]\.B`, "22", "int", noChildren)
 							validateEvaluateName(t, client, m4Val1, 0)
 							validateEvaluateName(t, client, m4Val1, 1)
 						}
 					}
-					expectVarExact(t, locals, -1, "emptymap", "emptymap", "map[string]string []", noChildren)
+					expectVarExact(t, locals, -1, "emptymap", "emptymap", "map[string]string []", "map[string]string", noChildren)
 					// reflect.Kind == Ptr
-					ref = expectVarExact(t, locals, -1, "pp1", "pp1", "**1", hasChildren)
+					ref = expectVarExact(t, locals, -1, "pp1", "pp1", "**1", "**int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						pp1val := client.ExpectVariablesResponse(t)
 						expectChildren(t, pp1val, "*pp1", 1)
-						ref = expectVarExact(t, pp1val, 0, "", "(*pp1)", "*1", hasChildren)
+						ref = expectVarExact(t, pp1val, 0, "", "(*pp1)", "*1", "*int", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							pp1valval := client.ExpectVariablesResponse(t)
 							expectChildren(t, pp1valval, "*(*pp1)", 1)
-							expectVarExact(t, pp1valval, 0, "", "(*(*pp1))", "1", noChildren)
+							expectVarExact(t, pp1valval, 0, "", "(*(*pp1))", "1", "int", noChildren)
 							validateEvaluateName(t, client, pp1valval, 0)
 						}
 					}
 					// reflect.Kind == Slice
-					ref = expectVarExact(t, locals, -1, "zsslice", "zsslice", "[]struct {} len: 3, cap: 3, [{},{},{}]", hasChildren)
+					ref = expectVarExact(t, locals, -1, "zsslice", "zsslice", "[]struct {} len: 3, cap: 3, [{},{},{}]", "[]struct {}", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						zsslice := client.ExpectVariablesResponse(t)
 						expectChildren(t, zsslice, "zsslice", 3)
-						expectVarExact(t, zsslice, 2, "[2]", "zsslice[2]", "struct {} {}", noChildren)
+						expectVarExact(t, zsslice, 2, "[2]", "zsslice[2]", "struct {} {}", "struct {}", noChildren)
 						validateEvaluateName(t, client, zsslice, 2)
 					}
-					expectVarExact(t, locals, -1, "emptyslice", "emptyslice", "[]string len: 0, cap: 0, []", noChildren)
-					expectVarExact(t, locals, -1, "nilslice", "nilslice", "[]int len: 0, cap: 0, nil", noChildren)
+					expectVarExact(t, locals, -1, "emptyslice", "emptyslice", "[]string len: 0, cap: 0, []", "[]string", noChildren)
+					expectVarExact(t, locals, -1, "nilslice", "nilslice", "[]int len: 0, cap: 0, nil", "[]int", noChildren)
 					// reflect.Kind == String
-					expectVarExact(t, locals, -1, "longstr", "longstr", "\"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more\"", noChildren)
+					expectVarExact(t, locals, -1, "longstr", "longstr", "\"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more\"", "string", noChildren)
 					// reflect.Kind == Struct
-					expectVarExact(t, locals, -1, "zsvar", "zsvar", "struct {} {}", noChildren)
+					expectVarExact(t, locals, -1, "zsvar", "zsvar", "struct {} {}", "struct {}", noChildren)
 					// reflect.Kind == UnsafePointer
 					// TODO(polina): how do I test for unsafe.Pointer(nil)?
-					expectVarRegex(t, locals, -1, "upnil", "upnil", `unsafe\.Pointer\(0x0\)`, noChildren)
-					expectVarRegex(t, locals, -1, "up1", "up1", `unsafe\.Pointer\(0x[0-9a-f]+\)`, noChildren)
+					expectVarRegex(t, locals, -1, "upnil", "upnil", `unsafe\.Pointer\(0x0\)`, "int", noChildren)
+					expectVarRegex(t, locals, -1, "up1", "up1", `unsafe\.Pointer\(0x[0-9a-f]+\)`, "int", noChildren)
 
 					// Test unreadable variable
-					ref = expectVarRegex(t, locals, -1, "unread", "unread", `\*\(unreadable .+\)`, hasChildren)
+					ref = expectVarRegex(t, locals, -1, "unread", "unread", `\*\(unreadable .+\)`, "int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						val := client.ExpectVariablesResponse(t)
 						expectChildren(t, val, "*unread", 1)
-						expectVarRegex(t, val, 0, "^$", `\(\*unread\)`, `\(unreadable .+\)`, noChildren)
+						expectVarRegex(t, val, 0, "^$", `\(\*unread\)`, `\(unreadable .+\)`, "int", noChildren)
 						validateEvaluateName(t, client, val, 0)
 					}
 				},
@@ -1400,10 +1413,10 @@ func TestVariablesLoading(t *testing.T) {
 					locals := client.ExpectVariablesResponse(t)
 
 					// String partially missing based on LoadConfig.MaxStringLen
-					expectVarExact(t, locals, -1, "longstr", "longstr", "\"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more\"", noChildren)
+					expectVarExact(t, locals, -1, "longstr", "longstr", "\"very long string 0123456789a0123456789b0123456789c0123456789d012...+73 more\"", "string", noChildren)
 
 					// Array partially missing based on LoadConfig.MaxArrayValues
-					ref := expectVarExact(t, locals, -1, "longarr", "longarr", "(loaded 64/100) [100]int [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+36 more]", hasChildren)
+					ref := expectVarExact(t, locals, -1, "longarr", "longarr", "(loaded 64/100) [100]int [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+36 more]", "[100]int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						longarr := client.ExpectVariablesResponse(t)
@@ -1411,7 +1424,7 @@ func TestVariablesLoading(t *testing.T) {
 					}
 
 					// Slice partially missing based on LoadConfig.MaxArrayValues
-					ref = expectVarExact(t, locals, -1, "longslice", "longslice", "(loaded 64/100) []int len: 100, cap: 100, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+36 more]", hasChildren)
+					ref = expectVarExact(t, locals, -1, "longslice", "longslice", "(loaded 64/100) []int len: 100, cap: 100, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+36 more]", "[]int", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						longarr := client.ExpectVariablesResponse(t)
@@ -1419,7 +1432,7 @@ func TestVariablesLoading(t *testing.T) {
 					}
 
 					// Map partially missing based on LoadConfig.MaxArrayValues
-					ref = expectVarRegex(t, locals, -1, "m1", "m1", `\(loaded 64/66\) map\[string\]main\.astruct \[.+\.\.\.\+2 more\]`, hasChildren)
+					ref = expectVarRegex(t, locals, -1, "m1", "m1", `\(loaded 64/66\) map\[string\]main\.astruct \[.+\.\.\.\+2 more\]`, `map\[string\]main\.astruct`, hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						m1 := client.ExpectVariablesResponse(t)
@@ -1427,7 +1440,7 @@ func TestVariablesLoading(t *testing.T) {
 					}
 
 					// Struct partially missing based on LoadConfig.MaxStructFields
-					ref = expectVarExact(t, locals, -1, "sd", "sd", "(loaded 5/6) main.D {u1: 0, u2: 0, u3: 0, u4: 0, u5: 0,...+1 more}", hasChildren)
+					ref = expectVarExact(t, locals, -1, "sd", "sd", "(loaded 5/6) main.D {u1: 0, u2: 0, u3: 0, u4: 0, u5: 0,...+1 more}", "main.D", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						sd := client.ExpectVariablesResponse(t)
@@ -1435,68 +1448,70 @@ func TestVariablesLoading(t *testing.T) {
 					}
 
 					// Fully missing struct auto-loaded when reaching LoadConfig.MaxVariableRecurse (also tests evaluateName corner case)
-					ref = expectVarRegex(t, locals, -1, "c1", "c1", `main\.cstruct {pb: \*main\.bstruct {a: \(\*main\.astruct\)\(0x[0-9a-f]+\)}, sa: []\*main\.astruct len: 3, cap: 3, [\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main.astruct\)\(0x[0-9a-f]+\)]}`, hasChildren)
+					ref = expectVarRegex(t, locals, -1, "c1", "c1", `main\.cstruct {pb: \*main\.bstruct {a: \(\*main\.astruct\)\(0x[0-9a-f]+\)}, sa: []\*main\.astruct len: 3, cap: 3, [\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main.astruct\)\(0x[0-9a-f]+\)]}`, `main\.cstruct`, hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						c1 := client.ExpectVariablesResponse(t)
 						expectChildren(t, c1, "c1", 2)
-						ref = expectVarRegex(t, c1, 1, "sa", `c1\.sa`, `\[\]\*main\.astruct len: 3, cap: 3, \[\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main\.astruct\)\(0x[0-9a-f]+\)\]`, hasChildren)
+						ref = expectVarRegex(t, c1, 1, "sa", `c1\.sa`, `\[\]\*main\.astruct len: 3, cap: 3, \[\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main\.astruct\)\(0x[0-9a-f]+\),\*\(\*main\.astruct\)\(0x[0-9a-f]+\)\]`, `\[\]\*main\.astruct`, hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							c1sa := client.ExpectVariablesResponse(t)
 							expectChildren(t, c1sa, "c1.sa", 3)
-							ref = expectVarRegex(t, c1sa, 0, `\[0\]`, `c1\.sa\[0\]`, `\*\(\*main\.astruct\)\(0x[0-9a-f]+\)`, hasChildren)
+							ref = expectVarRegex(t, c1sa, 0, `\[0\]`, `c1\.sa\[0\]`, `\*\(\*main\.astruct\)\(0x[0-9a-f]+\)`, `\*main\.astruct`, hasChildren)
 							if ref > 0 {
 								// Auto-loading of fully missing struc children happens here
 								client.VariablesRequest(ref)
 								c1sa0 := client.ExpectVariablesResponse(t)
 								expectChildren(t, c1sa0, "c1.sa[0]", 1)
-								expectVarExact(t, c1sa0, 0, "", "(*c1.sa[0])", "main.astruct {A: 1, B: 2}", hasChildren)
+								// TODO(polina): there should be children here once we support auto loading
+								expectVarExact(t, c1sa0, 0, "", "(*c1.sa[0])", "main.astruct {A: 1, B: 2}", "main.astruct", hasChildren)
 							}
 						}
 					}
 
 					// Fully missing struct auto-loaded when hitting LoadConfig.MaxVariableRecurse (also tests evaluteName corner case)
-					ref = expectVarRegex(t, locals, -1, "aas", "aas", `\[\]main\.a len: 1, cap: 1, \[{aas: \[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]}\]`, hasChildren)
+					ref = expectVarRegex(t, locals, -1, "aas", "aas", `\[\]main\.a len: 1, cap: 1, \[{aas: \[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]}\]`, `\[\]main\.a`, hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						aas := client.ExpectVariablesResponse(t)
 						expectChildren(t, aas, "aas", 1)
-						ref = expectVarRegex(t, aas, 0, "[0]", `aas\[0\]`, `main\.a {aas: \[\]main.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]}`, hasChildren)
+						ref = expectVarRegex(t, aas, 0, "[0]", `aas\[0\]`, `main\.a {aas: \[\]main.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]}`, `main\.a`, hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							aas0 := client.ExpectVariablesResponse(t)
 							expectChildren(t, aas0, "aas[0]", 1)
-							ref = expectVarRegex(t, aas0, 0, "aas", `aas\[0\]\.aas`, `\[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]`, hasChildren)
+							ref = expectVarRegex(t, aas0, 0, "aas", `aas\[0\]\.aas`, `\[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]`, `\[\]main\.a`, hasChildren)
 							if ref > 0 {
 								// Auto-loading of fully missing struct children happens here
 								client.VariablesRequest(ref)
 								aas0aas := client.ExpectVariablesResponse(t)
 								expectChildren(t, aas0aas, "aas[0].aas", 1)
-								ref = expectVarRegex(t, aas0aas, 0, "[0]", `aas\[0\]\.aas\[0\]`, `main\.a {aas: \[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]}`, hasChildren)
+								// TODO(polina): there should be a child here once we support auto loading - test for "aas[0].aas[0].aas"
+								ref = expectVarRegex(t, aas0aas, 0, "[0]", `aas\[0\]\.aas\[0\]`, `main\.a {aas: \[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]}`, "main.a", hasChildren)
 								if ref > 0 {
 									client.VariablesRequest(ref)
 									aas0aas0 := client.ExpectVariablesResponse(t)
 									expectChildren(t, aas0aas, "aas[0].aas[0]", 1)
-									expectVarRegex(t, aas0aas0, 0, "aas", `aas\[0\]\.aas\[0\]\.aas`, `\[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]`, hasChildren)
+									expectVarRegex(t, aas0aas0, 0, "aas", `aas\[0\]\.aas\[0\]\.aas`, `\[\]main\.a len: 1, cap: 1, \[\(\*main\.a\)\(0x[0-9a-f]+\)\]`, `\[\]main\.a`, hasChildren)
 								}
 							}
 						}
 					}
 
 					// Fully missing map auto-loaded when hitting LoadConfig.MaxVariableRecurse (also tests evaluateName corner case)
-					ref = expectVarExact(t, locals, -1, "tm", "tm", "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [[...]]}", hasChildren)
+					ref = expectVarExact(t, locals, -1, "tm", "tm", "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [[...]]}", "main.truncatedMap", hasChildren)
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						tm := client.ExpectVariablesResponse(t)
 						expectChildren(t, tm, "tm", 1)
-						ref = expectVarExact(t, tm, 0, "v", "tm.v", "[]map[string]main.astruct len: 1, cap: 1, [[...]]", hasChildren)
+						ref = expectVarExact(t, tm, 0, "v", "tm.v", "[]map[string]main.astruct len: 1, cap: 1, [[...]]", "[]map[string]main.astruct", hasChildren)
 						if ref > 0 {
 							// Auto-loading of fully missing map chidlren happens here, but they get trancated at MaxArrayValuess
 							client.VariablesRequest(ref)
 							tmV := client.ExpectVariablesResponse(t)
 							expectChildren(t, tmV, "tm.v", 1)
-							ref = expectVarRegex(t, tmV, 0, `\[0\]`, `tm\.v\[0\]`, `map\[string\]main\.astruct \[.+\.\.\.\+2 more\]`, hasChildren)
+							ref = expectVarRegex(t, tmV, 0, `\[0\]`, `tm\.v\[0\]`, `map\[string\]main\.astruct \[.+\.\.\.\+2 more\]`, `map\[string\]main\.astruct`, hasChildren)
 							if ref > 0 {
 								client.VariablesRequest(ref)
 								tmV0 := client.ExpectVariablesResponse(t)
@@ -1514,19 +1529,19 @@ func TestVariablesLoading(t *testing.T) {
 						client.VariablesRequest(ref)
 						rv := client.ExpectVariablesResponse(t)
 						expectChildren(t, rv, "rv", 1)
-						ref = expectVarExact(t, rv, 0, "~r0", "", "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [[...]]}", hasChildren)
+						ref = expectVarExact(t, rv, 0, "~r0", "", "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [[...]]}", "main.truncatedMap", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							tm := client.ExpectVariablesResponse(t)
 							expectChildren(t, tm, "tm", 1)
-							ref = expectVarExact(t, tm, 0, "v", "", "[]map[string]main.astruct len: 1, cap: 1, [[...]]", hasChildren)
+							ref = expectVarExact(t, tm, 0, "v", "", "[]map[string]main.astruct len: 1, cap: 1, [[...]]", "[]map[string]main.astruct", hasChildren)
 							if ref > 0 {
 								// Auto-loading of fully missing map chidlren happens here, but they get trancated at MaxArrayValuess
 								client.VariablesRequest(ref)
 								tmV := client.ExpectVariablesResponse(t)
 								expectChildren(t, tmV, "tm.v", 1)
 								// TODO(polina): this evaluate name is not usable - it should be empty
-								ref = expectVarRegex(t, tmV, 0, `\[0\]`, `\[0\]`, `map\[string\]main\.astruct \[.+\.\.\.\+2 more\]`, hasChildren)
+								ref = expectVarRegex(t, tmV, 0, `\[0\]`, `\[0\]`, `map\[string\]main\.astruct \[.+\.\.\.\+2 more\]`, `map\[string\]main\.astruct`, hasChildren)
 								if ref > 0 {
 									client.VariablesRequest(ref)
 									tmV0 := client.ExpectVariablesResponse(t)
@@ -1575,32 +1590,31 @@ func TestVariablesLoading(t *testing.T) {
 
 						// Interface auto-loaded when hitting LoadConfig.MaxVariableRecurse=1
 
-						ref := expectVarRegex(t, locals, -1, "ni", "ni", `\[\]interface {} len: 1, cap: 1, \[\[\]interface {} len: 1, cap: 1, \[\*\(\*interface {}\)\(0x[0-9a-f]+\)\]\]`, hasChildren)
+						ref := expectVarRegex(t, locals, -1, "ni", "ni", `\[\]interface {} len: 1, cap: 1, \[\[\]interface {} len: 1, cap: 1, \[\*\(\*interface {}\)\(0x[0-9a-f]+\)\]\]`, `\[\]interface {}`, hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							ni := client.ExpectVariablesResponse(t)
-							ref = expectVarRegex(t, ni, 0, `\[0\]`, `ni\[0\]`, `interface \{\}\(\[\]interface \{\}\) \[\*\(\*interface \{\}\)\(0x[0-9a-f]+\)\]`, hasChildren)
+							ref = expectVarRegex(t, ni, 0, `\[0\]`, `ni\[0\]`, `interface \{\}\(\[\]interface \{\}\) \[\*\(\*interface \{\}\)\(0x[0-9a-f]+\)\]`, "interface {}", hasChildren)
 							if ref > 0 {
 								client.VariablesRequest(ref)
 								niI1 := client.ExpectVariablesResponse(t)
-								ref = expectVarRegex(t, niI1, 0, "data", `ni\[0\]\.\(data\)`, `\[\]interface {} len: 1, cap: 1, \[\*\(\*interface {}\)\(0x[0-9a-f]+\)`, hasChildren)
+								ref = expectVarRegex(t, niI1, 0, "data", `ni\[0\]\.\(data\)`, `\[\]interface {} len: 1, cap: 1, \[\*\(\*interface {}\)\(0x[0-9a-f]+\)`, `\[\]interface {}`, hasChildren)
 								if ref > 0 {
 									// Auto-loading happens here
 									client.VariablesRequest(ref)
 									niI1Data := client.ExpectVariablesResponse(t)
-									ref = expectVarExact(t, niI1Data, 0, "[0]", "ni[0].(data)[0]", "interface {}(int) 123", hasChildren)
+									ref = expectVarExact(t, niI1Data, 0, "[0]", "ni[0].(data)[0]", "interface {}(int) 123", "interface {}", hasChildren)
 									if ref > 0 {
 										client.VariablesRequest(ref)
 										niI1DataI2 := client.ExpectVariablesResponse(t)
-										expectVarExact(t, niI1DataI2, 0, "data", "ni[0].(data)[0].(data)", "123", noChildren)
+										expectVarExact(t, niI1DataI2, 0, "data", "ni[0].(data)[0].(data)", "123", "int", noChildren)
 									}
 								}
 							}
 						}
 
 						// Pointer values loaded even with LoadConfig.FollowPointers=false
-
-						expectVarExact(t, locals, -1, "a7", "a7", "*main.FooBar {Baz: 5, Bur: \"strum\"}", hasChildren)
+						expectVarExact(t, locals, -1, "a7", "a7", "*main.FooBar {Baz: 5, Bur: \"strum\"}", "*main.FooBar", hasChildren)
 
 						// Auto-loading works on results of evaluate expressions as well
 						client.EvaluateRequest("a7", frame, "repl")
@@ -1612,7 +1626,7 @@ func TestVariablesLoading(t *testing.T) {
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							a7 := client.ExpectVariablesResponse(t)
-							expectVarExact(t, a7, 0, "a7", "(*(&a7))", "*main.FooBar {Baz: 5, Bur: \"strum\"}", hasChildren)
+							expectVarExact(t, a7, 0, "a7", "(*(&a7))", "*main.FooBar {Baz: 5, Bur: \"strum\"}", "*main.FooBar", hasChildren)
 						}
 					}
 
@@ -1684,14 +1698,14 @@ func TestGlobalScopeAndVariables(t *testing.T) {
 					client.VariablesRequest(1002)
 					globals := client.ExpectVariablesResponse(t)
 					expectChildren(t, globals, "Globals", 1)
-					ref := expectVarExact(t, globals, 0, "SomeVar", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeVar", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType {X: 0}", hasChildren)
+					ref := expectVarExact(t, globals, 0, "SomeVar", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeVar", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType {X: 0}", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType", hasChildren)
 
 					if ref > 0 {
 						client.VariablesRequest(ref)
 						somevar := client.ExpectVariablesResponse(t)
 						expectChildren(t, somevar, "SomeVar", 1)
 						// TODO(polina): unlike main.p, this prefix won't work
-						expectVarExact(t, somevar, 0, "X", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeVar.X", "0", noChildren)
+						expectVarExact(t, somevar, 0, "X", "github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeVar.X", "0", "float64", noChildren)
 					}
 				},
 				disconnect: false,
@@ -1728,8 +1742,8 @@ func TestShadowedVariables(t *testing.T) {
 					client.VariablesRequest(1001)
 					locals := client.ExpectVariablesResponse(t)
 
-					expectVarExact(t, locals, 0, "(a)", "a", "0", !hasChildren)
-					expectVarExact(t, locals, 1, "a", "a", "1", !hasChildren)
+					expectVarExact(t, locals, 0, "(a)", "a", "0", "int", !hasChildren)
+					expectVarExact(t, locals, 1, "a", "a", "1", "int", !hasChildren)
 
 					// Check that the non-shadowed of "a" is returned from evaluate request.
 					validateEvaluateName(t, client, locals, 1)
@@ -1764,6 +1778,32 @@ func TestLaunchRequestWithStackTraceDepth(t *testing.T) {
 	})
 }
 
+type Breakpoint struct {
+	line      int
+	path      string
+	verified  bool
+	msgPrefix string
+}
+
+func expectSetBreakpointsResponse(t *testing.T, client *daptest.Client, bps []Breakpoint) {
+	t.Helper()
+	checkSetBreakpointsResponse(t, client, bps, client.ExpectSetBreakpointsResponse(t))
+}
+
+func checkSetBreakpointsResponse(t *testing.T, client *daptest.Client, bps []Breakpoint, got *dap.SetBreakpointsResponse) {
+	t.Helper()
+	if len(got.Body.Breakpoints) != len(bps) {
+		t.Errorf("got %#v,\nwant len(Breakpoints)=%d", got, len(bps))
+		return
+	}
+	for i, bp := range got.Body.Breakpoints {
+		if bp.Line != bps[i].line || bp.Verified != bps[i].verified || bp.Source.Path != bps[i].path ||
+			!strings.HasPrefix(bp.Message, bps[i].msgPrefix) {
+			t.Errorf("got breakpoints[%d] = %#v, \nwant %#v", i, bp, bps[i])
+		}
+	}
+}
+
 // TestSetBreakpoint executes to a breakpoint and tests different
 // configurations of setBreakpoint requests.
 func TestSetBreakpoint(t *testing.T) {
@@ -1779,34 +1819,13 @@ func TestSetBreakpoint(t *testing.T) {
 				execute: func() {
 					handleStop(t, client, 1, "main.main", 16)
 
-					type Breakpoint struct {
-						line      int
-						path      string
-						verified  bool
-						msgPrefix string
-					}
-					expectSetBreakpointsResponse := func(bps []Breakpoint) {
-						t.Helper()
-						got := client.ExpectSetBreakpointsResponse(t)
-						if len(got.Body.Breakpoints) != len(bps) {
-							t.Errorf("got %#v,\nwant len(Breakpoints)=%d", got, len(bps))
-							return
-						}
-						for i, bp := range got.Body.Breakpoints {
-							if bp.Line != bps[i].line || bp.Verified != bps[i].verified || bp.Source.Path != bps[i].path ||
-								!strings.HasPrefix(bp.Message, bps[i].msgPrefix) {
-								t.Errorf("got breakpoints[%d] = %#v, \nwant %#v", i, bp, bps[i])
-							}
-						}
-					}
-
 					// Set two breakpoints at the next two lines in main
 					client.SetBreakpointsRequest(fixture.Source, []int{17, 18})
-					expectSetBreakpointsResponse([]Breakpoint{{17, fixture.Source, true, ""}, {18, fixture.Source, true, ""}})
+					expectSetBreakpointsResponse(t, client, []Breakpoint{{17, fixture.Source, true, ""}, {18, fixture.Source, true, ""}})
 
 					// Clear 17, reset 18
 					client.SetBreakpointsRequest(fixture.Source, []int{18})
-					expectSetBreakpointsResponse([]Breakpoint{{18, fixture.Source, true, ""}})
+					expectSetBreakpointsResponse(t, client, []Breakpoint{{18, fixture.Source, true, ""}})
 
 					// Skip 17, continue to 18
 					client.ContinueRequest(1)
@@ -1816,7 +1835,7 @@ func TestSetBreakpoint(t *testing.T) {
 
 					// Set another breakpoint inside the loop in loop(), twice to trigger error
 					client.SetBreakpointsRequest(fixture.Source, []int{8, 8})
-					expectSetBreakpointsResponse([]Breakpoint{{8, fixture.Source, true, ""}, {8, "", false, "Breakpoint exists"}})
+					expectSetBreakpointsResponse(t, client, []Breakpoint{{8, fixture.Source, true, ""}, {8, "", false, "Breakpoint exists"}})
 
 					// Continue into the loop
 					client.ContinueRequest(1)
@@ -1825,11 +1844,11 @@ func TestSetBreakpoint(t *testing.T) {
 					handleStop(t, client, 1, "main.loop", 8)
 					client.VariablesRequest(1001) // Locals
 					locals := client.ExpectVariablesResponse(t)
-					expectVarExact(t, locals, 0, "i", "i", "0", noChildren) // i == 0
+					expectVarExact(t, locals, 0, "i", "i", "0", "int", noChildren) // i == 0
 
 					// Edit the breakpoint to add a condition
 					client.SetConditionalBreakpointsRequest(fixture.Source, []int{8}, map[int]string{8: "i == 3"})
-					expectSetBreakpointsResponse([]Breakpoint{{8, fixture.Source, true, ""}})
+					expectSetBreakpointsResponse(t, client, []Breakpoint{{8, fixture.Source, true, ""}})
 
 					// Continue until condition is hit
 					client.ContinueRequest(1)
@@ -1838,11 +1857,11 @@ func TestSetBreakpoint(t *testing.T) {
 					handleStop(t, client, 1, "main.loop", 8)
 					client.VariablesRequest(1001) // Locals
 					locals = client.ExpectVariablesResponse(t)
-					expectVarExact(t, locals, 0, "i", "i", "3", noChildren) // i == 3
+					expectVarExact(t, locals, 0, "i", "i", "3", "int", noChildren) // i == 3
 
 					// Edit the breakpoint to remove a condition
 					client.SetConditionalBreakpointsRequest(fixture.Source, []int{8}, map[int]string{8: ""})
-					expectSetBreakpointsResponse([]Breakpoint{{8, fixture.Source, true, ""}})
+					expectSetBreakpointsResponse(t, client, []Breakpoint{{8, fixture.Source, true, ""}})
 
 					// Continue for one more loop iteration
 					client.ContinueRequest(1)
@@ -1851,11 +1870,11 @@ func TestSetBreakpoint(t *testing.T) {
 					handleStop(t, client, 1, "main.loop", 8)
 					client.VariablesRequest(1001) // Locals
 					locals = client.ExpectVariablesResponse(t)
-					expectVarExact(t, locals, 0, "i", "i", "4", noChildren) // i == 4
+					expectVarExact(t, locals, 0, "i", "i", "4", "int", noChildren) // i == 4
 
 					// Set at a line without a statement
 					client.SetBreakpointsRequest(fixture.Source, []int{1000})
-					expectSetBreakpointsResponse([]Breakpoint{{1000, "", false, "could not find statement"}}) // all cleared, none set
+					expectSetBreakpointsResponse(t, client, []Breakpoint{{1000, "", false, "could not find statement"}}) // all cleared, none set
 				},
 				// The program has an infinite loop, so we must kill it by disconnecting.
 				disconnect: true,
@@ -1863,6 +1882,78 @@ func TestSetBreakpoint(t *testing.T) {
 	})
 }
 
+func expectSetBreakpointsResponseAndStoppedEvent(t *testing.T, client *daptest.Client) (se *dap.StoppedEvent, br *dap.SetBreakpointsResponse) {
+	for i := 0; i < 2; i++ {
+		switch m := client.ExpectMessage(t).(type) {
+		case *dap.StoppedEvent:
+			se = m
+		case *dap.SetBreakpointsResponse:
+			br = m
+		default:
+			t.Fatalf("Unexpected message type: expect StoppedEvent or SetBreakpointsResponse, got %#v", m)
+		}
+	}
+	if se == nil || br == nil {
+		t.Fatal("Expected StoppedEvent and SetBreakpointsResponse")
+	}
+	return se, br
+}
+
+func TestSetBreakpointWhileRunning(t *testing.T) {
+	runTest(t, "integrationprog", func(client *daptest.Client, fixture protest.Fixture) {
+		runDebugSessionWithBPs(t, client, "launch",
+			// Launch
+			func() {
+				client.LaunchRequest("exec", fixture.Path, !stopOnEntry)
+			},
+			// Set breakpoints
+			fixture.Source, []int{16},
+			[]onBreakpoint{{
+				execute: func() {
+					// The program loops 3 times over lines 14-15-8-9-10-16
+					handleStop(t, client, 1, "main.main", 16) // Line that sleeps for 1 second
+
+					// We can set breakpoints while nexting
+					client.NextRequest(1)
+					client.ExpectNextResponse(t)
+					client.SetBreakpointsRequest(fixture.Source, []int{15}) // [16,] => [15,]
+					se, br := expectSetBreakpointsResponseAndStoppedEvent(t, client)
+					if se.Body.Reason != "pause" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 0 && se.Body.ThreadId != 1 {
+						t.Errorf("\ngot  %#v\nwant Reason='pause' AllThreadsStopped=true ThreadId=0/1", se)
+					}
+					checkSetBreakpointsResponse(t, client, []Breakpoint{{15, fixture.Source, true, ""}}, br)
+					// Halt cancelled next, so if we continue we will not stop at line 14.
+					client.ContinueRequest(1)
+					client.ExpectContinueResponse(t)
+					se = client.ExpectStoppedEvent(t)
+					if se.Body.Reason != "breakpoint" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 1 {
+						t.Errorf("\ngot  %#v\nwant Reason='breakpoint' AllThreadsStopped=true ThreadId=1", se)
+					}
+					handleStop(t, client, 1, "main.main", 15)
+
+					// We can set breakpoints while continuing
+					client.ContinueRequest(1)
+					client.ExpectContinueResponse(t)
+					client.SetBreakpointsRequest(fixture.Source, []int{9}) // [15,] => [9,]
+					se, br = expectSetBreakpointsResponseAndStoppedEvent(t, client)
+					if se.Body.Reason != "pause" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 0 && se.Body.ThreadId != 1 {
+						t.Errorf("\ngot  %#v\nwant Reason='pause' AllThreadsStopped=true ThreadId=0/1", se)
+					}
+					checkSetBreakpointsResponse(t, client, []Breakpoint{{9, fixture.Source, true, ""}}, br)
+					client.ContinueRequest(1)
+					client.ExpectContinueResponse(t)
+					se = client.ExpectStoppedEvent(t)
+					if se.Body.Reason != "breakpoint" || !se.Body.AllThreadsStopped || se.Body.ThreadId != 1 {
+						t.Errorf("\ngot  %#v\nwant Reason='breakpoint' AllThreadsStopped=true ThreadId=1", se)
+					}
+					handleStop(t, client, 1, "main.sayhi", 9)
+
+				},
+				disconnect: true,
+			}})
+	})
+}
+
 // TestLaunchSubstitutePath sets a breakpoint using a path
 // that does not exist and expects the substitutePath attribute
 // in the launch configuration to take care of the mapping.
@@ -1979,8 +2070,8 @@ func TestWorkingDir(t *testing.T) {
 					client.VariablesRequest(1001) // Locals
 					locals := client.ExpectVariablesResponse(t)
 					expectChildren(t, locals, "Locals", 2)
-					expectVarExact(t, locals, 0, "pwd", "pwd", fmt.Sprintf("%q", wd), noChildren)
-					expectVarExact(t, locals, 1, "err", "err", "error nil", noChildren)
+					expectVarExact(t, locals, 0, "pwd", "pwd", fmt.Sprintf("%q", wd), "string", noChildren)
+					expectVarExact(t, locals, 1, "err", "err", "error nil", "error", noChildren)
 
 				},
 				disconnect: false,
@@ -2033,8 +2124,8 @@ func TestEvaluateRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						a5 := client.ExpectVariablesResponse(t)
 						expectChildren(t, a5, "a5", 5)
-						expectVarExact(t, a5, 0, "[0]", "(a5)[0]", "1", noChildren)
-						expectVarExact(t, a5, 4, "[4]", "(a5)[4]", "5", noChildren)
+						expectVarExact(t, a5, 0, "[0]", "(a5)[0]", "1", "int", noChildren)
+						expectVarExact(t, a5, 4, "[4]", "(a5)[4]", "5", "int", noChildren)
 						validateEvaluateName(t, client, a5, 0)
 						validateEvaluateName(t, client, a5, 4)
 					}
@@ -2067,7 +2158,7 @@ func TestEvaluateRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						val := client.ExpectVariablesResponse(t)
 						expectChildren(t, val, "*(*int)(2)", 1)
-						expectVarRegex(t, val, 0, "^$", `\(\*\(\(\*int\)\(2\)\)\)`, `\(unreadable .+\)`, noChildren)
+						expectVarRegex(t, val, 0, "^$", `\(\*\(\(\*int\)\(2\)\)\)`, `\(unreadable .+\)`, "int", noChildren)
 						validateEvaluateName(t, client, val, 0)
 					}
 
@@ -2094,7 +2185,7 @@ func TestEvaluateRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						expr := client.ExpectVariablesResponse(t)
 						expectChildren(t, expr, "mp[1]", 1)
-						expectVarExact(t, expr, 0, "data", "(mp[1]).(data)", "42", noChildren)
+						expectVarExact(t, expr, 0, "data", "(mp[1]).(data)", "42", "int", noChildren)
 						validateEvaluateName(t, client, expr, 0)
 					}
 
@@ -2106,7 +2197,7 @@ func TestEvaluateRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						expr := client.ExpectVariablesResponse(t)
 						expectChildren(t, expr, "*ms.Nest", 2)
-						expectVarExact(t, expr, 0, "Level", "(*ms.Nest).Level", "1", noChildren)
+						expectVarExact(t, expr, 0, "Level", "(*ms.Nest).Level", "1", "int", noChildren)
 						validateEvaluateName(t, client, expr, 0)
 					}
 
@@ -2242,7 +2333,7 @@ func TestEvaluateCallRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						rv := client.ExpectVariablesResponse(t)
 						expectChildren(t, rv, "rv", 1)
-						expectVarExact(t, rv, 0, "~r2", "", "3", noChildren)
+						expectVarExact(t, rv, 0, "~r2", "", "3", "int", noChildren)
 					}
 					// One named return value
 					// Panic doesn't panic, but instead returns the error as a named return variable
@@ -2253,12 +2344,12 @@ func TestEvaluateCallRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						rv := client.ExpectVariablesResponse(t)
 						expectChildren(t, rv, "rv", 1)
-						ref = expectVarExact(t, rv, 0, "~panic", "", `interface {}(string) "callpanic panicked"`, hasChildren)
+						ref = expectVarExact(t, rv, 0, "~panic", "", `interface {}(string) "callpanic panicked"`, "interface {}", hasChildren)
 						if ref > 0 {
 							client.VariablesRequest(ref)
 							p := client.ExpectVariablesResponse(t)
 							expectChildren(t, p, "~panic", 1)
-							expectVarExact(t, p, 0, "data", "", "\"callpanic panicked\"", noChildren)
+							expectVarExact(t, p, 0, "data", "", "\"callpanic panicked\"", "string", noChildren)
 						}
 					}
 					// Multiple return values
@@ -2269,8 +2360,8 @@ func TestEvaluateCallRequest(t *testing.T) {
 						client.VariablesRequest(ref)
 						rvs := client.ExpectVariablesResponse(t)
 						expectChildren(t, rvs, "rvs", 2)
-						expectVarExact(t, rvs, 0, "~r2", "", "1", noChildren)
-						expectVarExact(t, rvs, 1, "~r3", "", "2", noChildren)
+						expectVarExact(t, rvs, 0, "~r2", "", "1", "int", noChildren)
+						expectVarExact(t, rvs, 1, "~r3", "", "2", "int", noChildren)
 					}
 					// No frame defaults to top-most frame
 					client.EvaluateRequest("call call1(one, two)", 0, "this context will be ignored")
@@ -2978,7 +3069,7 @@ func TestAttachRequest(t *testing.T) {
 					client.VariablesRequest(1001) // Locals
 					locals := client.ExpectVariablesResponse(t)
 					expectChildren(t, locals, "Locals", 1)
-					expectVarRegex(t, locals, 0, "i", "i", "[0-9]+", noChildren)
+					expectVarRegex(t, locals, 0, "i", "i", "[0-9]+", "int", noChildren)
 				},
 				disconnect: true,
 			}})
@@ -3130,14 +3221,6 @@ func TestBadLaunchRequests(t *testing.T) {
 			}
 		}
 
-		expectFailedToLaunchWithMessageRegex := func(response *dap.ErrorResponse, errmsg string) {
-			t.Helper()
-			expectFailedToLaunch(response)
-			if matched, _ := regexp.MatchString(errmsg, response.Body.Error.Format); !matched {
-				t.Errorf("\ngot  %q\nwant %q", response.Body.Error.Format, errmsg)
-			}
-		}
-
 		// Test for the DAP-specific detailed error message.
 		client.LaunchRequest("exec", "", stopOnEntry)
 		expectFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
@@ -3219,18 +3302,34 @@ func TestBadLaunchRequests(t *testing.T) {
 		expectFailedToLaunch(client.ExpectInvisibleErrorResponse(t)) // No such file or directory
 
 		client.LaunchRequest("debug", fixture.Path+"_does_not_exist", stopOnEntry)
+		oe := client.ExpectOutputEvent(t)
+		if !strings.HasPrefix(oe.Body.Output, "Build Error: ") || oe.Body.Category != "stderr" {
+			t.Errorf("got %#v, want Category=\"stderr\" Output=\"Build Error: ...\"", oe)
+		}
 		expectFailedToLaunch(client.ExpectInvisibleErrorResponse(t))
 
 		client.LaunchRequest("" /*debug by default*/, fixture.Path+"_does_not_exist", stopOnEntry)
+		oe = client.ExpectOutputEvent(t)
+		if !strings.HasPrefix(oe.Body.Output, "Build Error: ") || oe.Body.Category != "stderr" {
+			t.Errorf("got %#v, want Category=\"stderr\" Output=\"Build Error: ...\"", oe)
+		}
 		expectFailedToLaunch(client.ExpectInvisibleErrorResponse(t))
 
 		client.LaunchRequest("exec", fixture.Source, stopOnEntry)
 		expectFailedToLaunch(client.ExpectInvisibleErrorResponse(t)) // Not an executable
 
 		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "buildFlags": "-bad -flags"})
-		expectFailedToLaunchWithMessageRegex(client.ExpectInvisibleErrorResponse(t), `Failed to launch: Build error: .*flag provided but not defined.*`)
+		oe = client.ExpectOutputEvent(t)
+		if !strings.HasPrefix(oe.Body.Output, "Build Error: ") || oe.Body.Category != "stderr" {
+			t.Errorf("got %#v, want Category=\"stderr\" Output=\"Build Error: ...\"", oe)
+		}
+		expectFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t), "Failed to launch: Build error: Check the debug console for details.")
 		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "noDebug": true, "buildFlags": "-bad -flags"})
-		expectFailedToLaunchWithMessageRegex(client.ExpectInvisibleErrorResponse(t), `Failed to launch: Build error: .*flag provided but not defined.*`)
+		oe = client.ExpectOutputEvent(t)
+		if !strings.HasPrefix(oe.Body.Output, "Build Error: ") || oe.Body.Category != "stderr" {
+			t.Errorf("got %#v, want Category=\"stderr\" Output=\"Build Error: ...\"", oe)
+		}
+		expectFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t), "Failed to launch: Build error: Check the debug console for details.")
 
 		// Bad "wd".
 		client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "noDebug": false, "cwd": "dir/invalid"})