blob: 8993e1a2942a423b340e21c818bde35dd572d899 [file] [edit]
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:expect/expect.dart';
import 'package:expect/variations.dart';
// Prevent inlining and Binaryen duplicate-function-elimination so `exception1`
// and `exception2` remain distinct frames in stack traces when unminified.
@pragma('vm:never-inline')
@pragma('dart2js:noInline')
@pragma('wasm:never-inline')
void exception1(String e) {
if (identical(e, '1')) return;
throw e;
}
@pragma('vm:never-inline')
@pragma('dart2js:noInline')
@pragma('wasm:never-inline')
void exception2(String e) {
if (identical(e, '2')) return;
throw e;
}
@pragma('vm:never-inline')
@pragma('dart2js:noInline')
@pragma('wasm:never-inline')
void doSyncThrow1() {
try {
exception1('outer');
} on Object {
try {
exception2('inner');
} on Object {
// ignore
}
rethrow;
}
}
@pragma('vm:never-inline')
@pragma('dart2js:noInline')
@pragma('wasm:never-inline')
void doSyncThrow2() {
try {
exception2('outer');
} on Object {
try {
exception1('inner');
} on Object {
try {
exception1('more inner');
} on Object {
// ignore
}
}
rethrow;
}
}
@pragma('vm:never-inline')
@pragma('dart2js:noInline')
@pragma('wasm:never-inline')
void doSyncThrow3() {
try {
exception1('outer');
} on Object {
try {
// don't throw
} on Object {
try {
// also don't throw
} on Object {
// ignore
}
}
rethrow;
}
}
@pragma('vm:never-inline')
@pragma('dart2js:noInline')
@pragma('wasm:never-inline')
void doSyncThrow4() {
try {
exception1('outer');
} on Object {
try {
exception2('inner');
} on bool {}
rethrow;
}
}
@pragma('vm:never-inline')
@pragma('dart2js:noInline')
@pragma('wasm:never-inline')
void doSyncThrowFinally() {
try {
exception1('outer');
} finally {
// empty finalizer
}
}
@pragma('vm:never-inline')
@pragma('dart2js:noInline')
@pragma('wasm:never-inline')
void doSyncThrowNestedFinally() {
try {
exception1('outer');
} finally {
try {
exception2('inner');
} on Object {
// ignore
}
}
}
@pragma('vm:never-inline')
@pragma('dart2js:noInline')
@pragma('wasm:never-inline')
List<String> testTryFinallyInLoop() {
final log = <String>[];
for (int i = 0; i < 4; i++) {
label:
try {
log.add('try:$i');
if (i == 0) {
break label;
}
if (i == 1) {
try {
throw 'err';
} finally {
log.add('inner-finally:$i');
}
}
} catch (e) {
log.add('catch:$i:$e');
} finally {
log.add('finally:$i');
}
log.add('after:$i');
}
return log;
}
void main() {
try {
doSyncThrow1();
Expect.fail('should throw');
} catch (e, s) {
Expect.equals(e, 'outer');
if (symbolicUnminifiedStackTraces) {
// Verify stack trace integrity of the rethrow when symbols are preserved
Expect.isTrue('$s'.contains('exception1'));
Expect.isTrue('$s'.contains('doSyncThrow1'));
}
}
try {
doSyncThrow2();
Expect.fail('should throw');
} catch (e, s) {
Expect.equals(e, 'outer');
if (symbolicUnminifiedStackTraces) {
Expect.isTrue('$s'.contains('exception2'));
Expect.isTrue('$s'.contains('doSyncThrow2'));
}
}
try {
doSyncThrow3();
Expect.fail('should throw');
} catch (e, s) {
Expect.equals(e, 'outer');
if (symbolicUnminifiedStackTraces) {
Expect.isTrue('$s'.contains('exception1'));
Expect.isTrue('$s'.contains('doSyncThrow3'));
}
}
try {
doSyncThrow4();
Expect.fail('should throw');
} catch (e, s) {
Expect.equals(e, 'inner');
if (symbolicUnminifiedStackTraces) {
Expect.isTrue('$s'.contains('exception2'));
Expect.isTrue('$s'.contains('doSyncThrow4'));
}
}
try {
doSyncThrowFinally();
Expect.fail('should throw');
} catch (e, s) {
Expect.equals(e, 'outer');
if (symbolicUnminifiedStackTraces) {
Expect.isTrue('$s'.contains('exception1'));
Expect.isTrue('$s'.contains('doSyncThrowFinally'));
}
}
try {
doSyncThrowNestedFinally();
Expect.fail('should throw');
} catch (e, s) {
Expect.equals(e, 'outer');
if (symbolicUnminifiedStackTraces) {
Expect.isTrue('$s'.contains('exception1'));
Expect.isTrue('$s'.contains('doSyncThrowNestedFinally'));
}
}
Expect.listEquals([
'try:0',
'finally:0',
'after:0',
'try:1',
'inner-finally:1',
'catch:1:err',
'finally:1',
'after:1',
'try:2',
'finally:2',
'after:2',
'try:3',
'finally:3',
'after:3',
], testTryFinallyInLoop());
}