| // Copyright (c) 2024, 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. | |
| /// Behavior variations of the current Dart execution. | |
| /// | |
| /// Dart compilers vary the behavior of the compiled code in certain predictable | |
| /// ways depending on the target platform or optimization flags, for example. | |
| /// | |
| /// When writing SDK or language tests, the tests should be aware of, and | |
| /// account for, those variations. | |
| /// | |
| /// The properties in this library are used to narrow expectations in SDK tests. | |
| /// That helps preserve test coverage in the presence of behavior variations in | |
| /// Dart implementations and testing configurations. | |
| /// | |
| /// Some variations in behavior are language compliant: | |
| /// | |
| /// * [number semantics][1] change when targeting JavaScript | |
| /// * some features have modalities (whether assertions are enabled, weak vs | |
| /// sound null safety), | |
| /// * some compilers support a subset of SDK libraries (for example, `dart:io` | |
| /// on native platforms), and | |
| /// * some behaviors are purposely unspecified (such as string representation | |
| /// of types, which can change in the presence of minification | |
| /// optimizations). | |
| /// | |
| /// Some variations can result from unsafe optimizations. These are deviations | |
| /// from the language or library contracts. Typically, this is done by backends | |
| /// like dart2js or dart2wasm that run on a sandboxed environment which limits | |
| /// the consequences of an erroneous optimization. Examples include: | |
| /// | |
| /// * omitting covariant and dynamic parameter checks | |
| /// * omitting implicit or explicit downcasts | |
| /// * bypassing checks in library code, like range checks when accessing | |
| /// native arrays in JavaScript. | |
| /// | |
| /// Regardless of the reason, variations are deliberate and should be accounted | |
| /// for in testing. Each behavior in this library is based on an underlying | |
| /// variation in an existing Dart implementation. | |
| /// | |
| /// Note: A coarse-grain alternative for each of these is also available in the | |
| /// `test_runner` infrastructure for narrowing expectations on entire test | |
| /// files. | |
| /// | |
| /// [1]: https://dart.dev/guides/language/numbers "Numbers in Dart" | |
| // TODO(54798): include conditions for VM/AOT/Wasm backends (current | |
| // definitions only reflect variations under dart2js and DDC compilers). | |
| // TODO(54798): update this dartdoc to also have a link to the standard | |
| // reference of variations when it becomes available in the SDK wiki. | |
| library; | |
| import 'config.dart'; | |
| /// Whether `assert`s are enabled. | |
| // TODO: If information can be made available as a constant, use that. | |
| // (For example if we introduce a compilation-environment entry for it.) | |
| final bool enabledAsserts = (() { | |
| bool result = false; | |
| assert(result = true); | |
| return result; | |
| })(); | |
| /// Whether the program is running without sound null safety. | |
| const bool unsoundNullSafety = <Null>[] is List<Object>; | |
| /// Whether the program is running with JavaScript [number semantics][1]. | |
| /// | |
| /// In code compiled to JavaScript, Dart integers are represented by JavaScript | |
| /// numbers, which have different ranges and behavior than native integers. | |
| /// | |
| /// For example, using JavaScript numbers, an `int` value like `1` also | |
| /// implements `double` and is the same object as `1.0`. In native numbers, | |
| /// those values are two different objects, and integers do not implement | |
| /// `double`. | |
| /// | |
| /// _Note: We do not use the term web-numbers because the Dart Wasm backend is | |
| /// considered a web backend, but uses native number semantics._ | |
| /// | |
| /// [1]: https://dart.dev/guides/language/numbers "Numbers in Dart" | |
| const bool jsNumbers = identical(1, 1.0); | |
| /// Whether [Type.toString] exposes the source names of types. | |
| /// | |
| /// If so, the strings are readable and can be used to match certain | |
| /// expectations. Typically this is not the case in production configurations | |
| /// that enable minification, like `dart compile js -O2` and `dart compile exe`. | |
| bool get readableTypeStrings => | |
| !const bool.fromEnvironment('dart.tool.dart2js.minify') && | |
| !const bool.fromEnvironment('dart.tool.dart2wasm.minify') && | |
| !(isVmConfiguration && configAsString.contains('obfuscate')); | |
| /// Whether [Symbol]s were minified. | |
| /// | |
| /// If [Symbol]s are minified, rruntime allocated `Symbol` objects | |
| /// will not compare equal to const `Symbols` (e.g., `new Symbol('x') != #x`). | |
| bool get minifiedSymbols => | |
| const bool.fromEnvironment('dart.tool.dart2wasm.minify'); | |
| /// Whether stack traces contain symbolic, unminified function names. | |
| bool get symbolicUnminifiedStackTraces => | |
| !const bool.fromEnvironment('dart.tool.dart2js.minify') && | |
| !const bool.fromEnvironment('dart.tool.dart2wasm.minify') && | |
| !(isVmConfiguration && | |
| (configAsString.contains('obfuscate') || | |
| configAsString.contains('dwarf'))); | |
| /// Whether specific subtypes of [Error] with details are thrown or generic | |
| /// [Error]s. | |
| bool get preciseErrorsWithDetails => | |
| !const bool.fromEnvironment('dart.tool.dart2wasm.minify'); | |
| /// Whether thrown [Error] objects will have a [StackTrace] attached. | |
| bool get errorsHaveStackTrace => | |
| !const bool.fromEnvironment('dart.tool.dart2wasm.minify'); | |
| /// Whether runtime parameter type checks are enforced. | |
| /// | |
| /// Runtime parameter type checks include both covariant parameter checks, | |
| /// either from generics or declared as `covariant`, and parameter checks of | |
| /// dynamic function invocations through `dynamic` or `Function`. | |
| /// | |
| /// For example, this code should fail a covariant parameter check: | |
| /// | |
| /// ```dart | |
| /// List<Object> list = <String>[]; | |
| /// list.add(1); | |
| /// ``` | |
| /// | |
| /// And this code should fail a dynamic invocation parameter type check: | |
| /// | |
| /// ```dart | |
| /// class A { | |
| /// m(int x) {} | |
| /// } | |
| /// (A() as dynamic).m("value"); | |
| /// ``` | |
| bool get checkedParameters => | |
| !const bool.fromEnvironment('dart.tool.dart2js.types:trust'); | |
| /// Whether implicit downcasts from `dynamic` are typed checked at runtime. | |
| /// | |
| /// The language allows an expression of type `dynamic` to be used | |
| /// where any other type is required, by doing a runtime check that | |
| /// the value has the required type. | |
| /// This value is `false` when that runtime check is omitted. | |
| /// | |
| /// For example, this code should fail with an invalid implicit cast: | |
| /// ```dart | |
| /// dynamic d = 3; String s = d; | |
| /// ``` | |
| bool get checkedImplicitDowncasts => | |
| !const bool.fromEnvironment('dart.tool.dart2js.types:trust'); | |
| /// Whether RTI optimizations are disabled at compile time. | |
| /// | |
| /// This can cause some type errors to present differently than they otherwise | |
| /// would. For example, when these optimizations are disabled ArgumentErrors may | |
| /// present as TypeErrors instead. | |
| bool get rtiOptimizationsDisabled => const bool.fromEnvironment( | |
| 'dart.tool.dart2js.disable_rti_optimization', | |
| defaultValue: true, | |
| ); | |
| /// Whether explicit casts are type checked at runtime. | |
| /// | |
| /// An expression like `e as String` should perform a runtime check that the | |
| /// value of `e` implements `String`. | |
| /// This value is `false` when that runtime check is omitted, and the runtime | |
| /// code will just use the value of `e` assuming it to be a string. | |
| /// | |
| /// For example, this code should fail the explicit cast when the integer `3` is | |
| /// checked for being a `String`: | |
| /// | |
| /// ```dart | |
| /// Object o = 3; | |
| /// o as String; | |
| /// ``` | |
| bool get checkedExplicitCasts => true; |