Chain.forTrace() falls back on VM stack chains

This wasn't happening previously when it was called synchronously
within Chain.capture().
diff --git a/pkgs/stack_trace/CHANGELOG.md b/pkgs/stack_trace/CHANGELOG.md
index e8e717e..916448c 100644
--- a/pkgs/stack_trace/CHANGELOG.md
+++ b/pkgs/stack_trace/CHANGELOG.md
@@ -4,6 +4,10 @@
   within `Chain.capture()`, even those that haven't been processed by
   `dart:async` yet.
 
+* `Chain.forTrace()` now uses the Dart VM's stack chain information when called
+  synchronously within `Chain.capture()`. This matches the existing behavior
+  outside `Chain.capture()`.
+
 ## 1.8.2
 
 * Update to use strong-mode clean Zone API.
diff --git a/pkgs/stack_trace/lib/src/chain.dart b/pkgs/stack_trace/lib/src/chain.dart
index 01bf06f..56c5333 100644
--- a/pkgs/stack_trace/lib/src/chain.dart
+++ b/pkgs/stack_trace/lib/src/chain.dart
@@ -153,6 +153,7 @@
   factory Chain.forTrace(StackTrace trace) {
     if (trace is Chain) return trace;
     if (_currentSpec != null) return _currentSpec.chainFor(trace);
+    if (trace is Trace) return new Chain([trace]);
     return new LazyChain(() => new Chain.parse(trace.toString()));
   }
 
diff --git a/pkgs/stack_trace/lib/src/stack_zone_specification.dart b/pkgs/stack_trace/lib/src/stack_zone_specification.dart
index 7205a4e..2db98b7 100644
--- a/pkgs/stack_trace/lib/src/stack_zone_specification.dart
+++ b/pkgs/stack_trace/lib/src/stack_zone_specification.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 
 import 'chain.dart';
+import 'lazy_chain.dart';
 import 'lazy_trace.dart';
 import 'trace.dart';
 import 'utils.dart';
@@ -86,8 +87,16 @@
   /// with [trace], this just returns a single-trace chain containing [trace].
   Chain chainFor(StackTrace trace) {
     if (trace is Chain) return trace;
-    var previous = (trace == null ? null : _chains[trace]) ?? _currentNode;
-    return new _Node(trace, previous).toChain();
+    trace ??= StackTrace.current;
+
+    var previous = _chains[trace] ?? _currentNode;
+    if (previous != null) return new _Node(trace, previous).toChain();
+
+    // If there's no [_currentNode], we're running synchronously beneath
+    // [Chain.capture] and we should fall back to the VM's stack chaining. We
+    // can't use [Chain.from] here because it'll just call [chainFor] again.
+    if (trace is Trace) return new Chain([trace]);
+    return new LazyChain(() => new Chain.parse(trace.toString()));
   }
 
   /// Tracks the current stack chain so it can be set to [_currentChain] when
diff --git a/pkgs/stack_trace/test/chain/vm_test.dart b/pkgs/stack_trace/test/chain/vm_test.dart
index 3378bc2..6f793c4 100644
--- a/pkgs/stack_trace/test/chain/vm_test.dart
+++ b/pkgs/stack_trace/test/chain/vm_test.dart
@@ -18,12 +18,21 @@
 
 void main() {
   group('capture() with onError catches exceptions', () {
-    test('thrown synchronously', () {
-      return captureFuture(() => throw 'error').then((chain) {
-        expect(chain.traces, hasLength(1));
-        expect(
-            chain.traces.single.frames.first, frameMember(startsWith('main')));
+    test('thrown synchronously', () async {
+      StackTrace vmTrace;
+      var chain = await captureFuture(() {
+        try {
+          throw 'error';
+        } catch (_, stackTrace) {
+          vmTrace = stackTrace;
+          rethrow;
+        }
       });
+
+      // Because there's no chain context for a synchronous error, we fall back
+      // on the VM's stack chain tracking.
+      expect(chain.toString(),
+          equals(new Chain.parse(vmTrace.toString()).toString()));
     });
 
     test('thrown in a microtask', () {