9e23810b77
Change-Id: I249c9fa9f2727544f940b3d954ce49bf38ee4918 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/191402 Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
601 lines
22 KiB
Dart
601 lines
22 KiB
Dart
// Copyright (c) 2016, 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.
|
|
|
|
library kernel.target.targets;
|
|
|
|
import '../ast.dart';
|
|
import '../class_hierarchy.dart';
|
|
import '../core_types.dart';
|
|
import '../reference_from_index.dart';
|
|
import 'changed_structure_notifier.dart';
|
|
|
|
final List<String> targetNames = targets.keys.toList();
|
|
|
|
class TargetFlags {
|
|
final bool trackWidgetCreation;
|
|
final int forceLateLoweringsForTesting;
|
|
final bool forceLateLoweringSentinelForTesting;
|
|
final bool forceStaticFieldLoweringForTesting;
|
|
final bool forceNoExplicitGetterCallsForTesting;
|
|
final bool enableNullSafety;
|
|
|
|
const TargetFlags(
|
|
{this.trackWidgetCreation = false,
|
|
this.forceLateLoweringsForTesting = LateLowering.none,
|
|
this.forceLateLoweringSentinelForTesting = false,
|
|
this.forceStaticFieldLoweringForTesting = false,
|
|
this.forceNoExplicitGetterCallsForTesting = false,
|
|
this.enableNullSafety = false});
|
|
|
|
bool operator ==(other) {
|
|
if (identical(this, other)) return true;
|
|
return other is TargetFlags &&
|
|
trackWidgetCreation == other.trackWidgetCreation &&
|
|
forceLateLoweringsForTesting == other.forceLateLoweringsForTesting &&
|
|
forceLateLoweringSentinelForTesting ==
|
|
other.forceLateLoweringSentinelForTesting &&
|
|
forceStaticFieldLoweringForTesting ==
|
|
other.forceStaticFieldLoweringForTesting &&
|
|
forceNoExplicitGetterCallsForTesting ==
|
|
other.forceNoExplicitGetterCallsForTesting &&
|
|
enableNullSafety == other.enableNullSafety;
|
|
}
|
|
|
|
int get hashCode {
|
|
int hash = 485786;
|
|
hash = 0x3fffffff & (hash * 31 + (hash ^ trackWidgetCreation.hashCode));
|
|
hash = 0x3fffffff &
|
|
(hash * 31 + (hash ^ forceLateLoweringsForTesting.hashCode));
|
|
hash = 0x3fffffff &
|
|
(hash * 31 + (hash ^ forceLateLoweringSentinelForTesting.hashCode));
|
|
hash = 0x3fffffff &
|
|
(hash * 31 + (hash ^ forceStaticFieldLoweringForTesting.hashCode));
|
|
hash = 0x3fffffff &
|
|
(hash * 31 + (hash ^ forceNoExplicitGetterCallsForTesting.hashCode));
|
|
hash = 0x3fffffff & (hash * 31 + (hash ^ enableNullSafety.hashCode));
|
|
return hash;
|
|
}
|
|
}
|
|
|
|
typedef Target _TargetBuilder(TargetFlags flags);
|
|
|
|
final Map<String, _TargetBuilder> targets = <String, _TargetBuilder>{
|
|
'none': (TargetFlags flags) => new NoneTarget(flags),
|
|
};
|
|
|
|
Target? getTarget(String name, TargetFlags flags) {
|
|
_TargetBuilder? builder = targets[name];
|
|
if (builder == null) return null;
|
|
return builder(flags);
|
|
}
|
|
|
|
abstract class DiagnosticReporter<M, C> {
|
|
void report(M message, int charOffset, int length, Uri fileUri,
|
|
{List<C> context});
|
|
}
|
|
|
|
/// The different kinds of number semantics supported by the constant evaluator.
|
|
enum NumberSemantics {
|
|
/// Dart VM number semantics.
|
|
vm,
|
|
|
|
/// JavaScript (Dart2js and DDC) number semantics.
|
|
js,
|
|
}
|
|
|
|
// Backend specific constant evaluation behavior
|
|
class ConstantsBackend {
|
|
const ConstantsBackend();
|
|
|
|
/// Lowering of a list constant to a backend-specific representation.
|
|
Constant lowerListConstant(ListConstant constant) => constant;
|
|
|
|
/// Returns `true` if [constant] is lowered list constant created by
|
|
/// [lowerListConstant].
|
|
bool isLoweredListConstant(Constant constant) => false;
|
|
|
|
/// Calls `f` for each element in the lowered list [constant].
|
|
///
|
|
/// This assumes that `isLoweredListConstant(constant)` is true.
|
|
void forEachLoweredListConstantElement(
|
|
Constant constant, void Function(Constant element) f) {}
|
|
|
|
/// Lowering of a set constant to a backend-specific representation.
|
|
Constant lowerSetConstant(SetConstant constant) => constant;
|
|
|
|
/// Returns `true` if [constant] is lowered set constant created by
|
|
/// [lowerSetConstant].
|
|
bool isLoweredSetConstant(Constant constant) => false;
|
|
|
|
/// Calls `f` for each element in the lowered set [constant].
|
|
///
|
|
/// This assumes that `isLoweredSetConstant(constant)` is true.
|
|
void forEachLoweredSetConstantElement(
|
|
Constant constant, void Function(Constant element) f) {}
|
|
|
|
/// Lowering of a map constant to a backend-specific representation.
|
|
Constant lowerMapConstant(MapConstant constant) => constant;
|
|
|
|
/// Returns `true` if [constant] is lowered map constant created by
|
|
/// [lowerMapConstant].
|
|
bool isLoweredMapConstant(Constant constant) => false;
|
|
|
|
/// Calls `f` for each key/value pair in the lowered map [constant].
|
|
///
|
|
/// This assumes that `lowerMapConstant(constant)` is true.
|
|
void forEachLoweredMapConstantEntry(
|
|
Constant constant, void Function(Constant key, Constant value) f) {}
|
|
|
|
/// Number semantics to use for this backend.
|
|
NumberSemantics get numberSemantics => NumberSemantics.vm;
|
|
|
|
/// Inline control of constant variables. The given constant expression
|
|
/// is the initializer of a [Field] or [VariableDeclaration] node.
|
|
/// If this method returns `true`, the variable will be inlined at all
|
|
/// points of reference and the variable itself removed (unless overridden
|
|
/// by the `keepFields` or `keepLocals` properties).
|
|
/// This method must be deterministic, i.e. it must always return the same
|
|
/// value for the same constant value and place in the AST.
|
|
bool shouldInlineConstant(ConstantExpression initializer) => true;
|
|
|
|
/// Whether this target supports unevaluated constants.
|
|
///
|
|
/// If not, then trying to perform constant evaluation without an environment
|
|
/// raises an exception.
|
|
///
|
|
/// This defaults to `false` since it requires additional work for a backend
|
|
/// to support unevaluated constants.
|
|
bool get supportsUnevaluatedConstants => false;
|
|
|
|
/// If `true` constant [Field] declarations are not removed from the AST even
|
|
/// when use-sites are inlined.
|
|
///
|
|
/// All use-sites will be rewritten based on [shouldInlineConstant].
|
|
bool get keepFields => true;
|
|
|
|
/// If `true` constant [VariableDeclaration]s are not removed from the AST
|
|
/// even when use-sites are inlined.
|
|
///
|
|
/// All use-sites will be rewritten based on [shouldInlineConstant].
|
|
bool get keepLocals => false;
|
|
}
|
|
|
|
/// A target provides backend-specific options for generating kernel IR.
|
|
abstract class Target {
|
|
TargetFlags get flags;
|
|
String get name;
|
|
|
|
/// A list of URIs of required libraries, not including dart:core.
|
|
///
|
|
/// Libraries will be loaded in order.
|
|
List<String> get extraRequiredLibraries => const <String>[];
|
|
|
|
/// A list of URIs of extra required libraries when compiling the platform.
|
|
///
|
|
/// Libraries will be loaded in order after the [extraRequiredLibraries]
|
|
/// above.
|
|
///
|
|
/// Normally not needed, but can be useful if removing libraries from the
|
|
/// [extraRequiredLibraries] list so libraries will still be available in the
|
|
/// platform if having a weird mix of current and not-quite-current as can
|
|
/// sometimes be the case.
|
|
List<String> get extraRequiredLibrariesPlatform => const <String>[];
|
|
|
|
/// A list of URIs of libraries to be indexed in the CoreTypes index, not
|
|
/// including dart:_internal, dart:async, dart:core and dart:mirrors.
|
|
List<String> get extraIndexedLibraries => const <String>[];
|
|
|
|
/// Additional declared variables implied by this target.
|
|
///
|
|
/// These can also be passed on the command-line of form `-D<name>=<value>`,
|
|
/// and those provided on the command-line take precedence over those defined
|
|
/// by the target.
|
|
Map<String, String> get extraDeclaredVariables => const <String, String>{};
|
|
|
|
/// Classes from the SDK whose interface is required for the modular
|
|
/// transformations.
|
|
Map<String, List<String>> get requiredSdkClasses => CoreTypes.requiredClasses;
|
|
|
|
/// A derived class may change this to `true` to enable forwarders to
|
|
/// user-defined `noSuchMethod` that are generated for each abstract member
|
|
/// if such `noSuchMethod` is present.
|
|
///
|
|
/// The forwarders are abstract [Procedure]s with [isNoSuchMethodForwarder]
|
|
/// bit set. The implementation of the behavior of such forwarders is up
|
|
/// for the target backend.
|
|
bool get enableNoSuchMethodForwarders => false;
|
|
|
|
/// A derived class may change this to `true` to enable Flutter specific
|
|
/// "super-mixins" semantics.
|
|
///
|
|
/// This semantics relaxes a number of constraint previously imposed on
|
|
/// mixins. Importantly it imposes the following change:
|
|
///
|
|
/// An abstract class may contain a member with a super-invocation that
|
|
/// corresponds to a member of the superclass interface, but where the
|
|
/// actual superclass does not declare or inherit a matching method.
|
|
/// Since no amount of overriding can change this property, such a class
|
|
/// cannot be extended to a class that is not abstract, it can only be
|
|
/// used to derive a mixin from.
|
|
///
|
|
/// See dartbug.com/31542 for details of the semantics.
|
|
bool get enableSuperMixins => false;
|
|
|
|
/// Perform target-specific transformations on the outlines stored in
|
|
/// [Component] when generating summaries.
|
|
///
|
|
/// This transformation is used to add metadata on outlines and to filter
|
|
/// unnecessary information before generating program summaries. This
|
|
/// transformation is not applied when compiling full kernel programs to
|
|
/// prevent affecting the internal invariants of the compiler and accidentally
|
|
/// slowing down compilation.
|
|
void performOutlineTransformations(Component component) {}
|
|
|
|
/// Perform target-specific transformations on the given libraries that must
|
|
/// run before constant evaluation.
|
|
void performPreConstantEvaluationTransformations(
|
|
Component component,
|
|
CoreTypes coreTypes,
|
|
List<Library> libraries,
|
|
DiagnosticReporter diagnosticReporter,
|
|
{void Function(String msg)? logger,
|
|
ChangedStructureNotifier? changedStructureNotifier}) {}
|
|
|
|
/// Perform target-specific modular transformations on the given libraries.
|
|
void performModularTransformationsOnLibraries(
|
|
Component component,
|
|
CoreTypes coreTypes,
|
|
ClassHierarchy hierarchy,
|
|
List<Library> libraries,
|
|
// TODO(askesc): Consider how to generally pass compiler options to
|
|
// transformations.
|
|
Map<String, String> environmentDefines,
|
|
DiagnosticReporter diagnosticReporter,
|
|
ReferenceFromIndex referenceFromIndex,
|
|
{void logger(String msg),
|
|
ChangedStructureNotifier changedStructureNotifier});
|
|
|
|
/// Perform target-specific modular transformations on the given program.
|
|
///
|
|
/// This is used when an individual expression is compiled, e.g. for debugging
|
|
/// purposes. It is illegal to modify any of the enclosing nodes of the
|
|
/// procedure.
|
|
void performTransformationsOnProcedure(
|
|
CoreTypes coreTypes, ClassHierarchy hierarchy, Procedure procedure,
|
|
{void Function(String msg)? logger}) {}
|
|
|
|
/// Whether a platform library may define a restricted type, such as `bool`,
|
|
/// `int`, `double`, `num`, and `String`.
|
|
///
|
|
/// By default only `dart:core` may define restricted types, but some target
|
|
/// implementations override this.
|
|
bool mayDefineRestrictedType(Uri uri) =>
|
|
uri.scheme == 'dart' && uri.path == 'core';
|
|
|
|
/// Whether a library is allowed to import a platform private library.
|
|
///
|
|
/// By default only `dart:*` libraries are allowed. May be overridden for
|
|
/// testing purposes.
|
|
bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) =>
|
|
imported.scheme != "dart" ||
|
|
!imported.path.startsWith("_") ||
|
|
importer.scheme == "dart" ||
|
|
(importer.scheme == "package" &&
|
|
importer.path.startsWith("dart_internal/"));
|
|
|
|
/// Whether the `native` language extension is supported within [library].
|
|
///
|
|
/// The `native` language extension is not part of the language specification,
|
|
/// it means something else to each target, and it is enabled under different
|
|
/// circumstances for each target implementation. For example, the VM target
|
|
/// enables it everywhere because of existing support for "dart-ext:" native
|
|
/// extensions, but targets like dart2js only enable it on the core libraries.
|
|
bool enableNative(Uri uri) => false;
|
|
|
|
/// There are two variants of the `native` language extension. The VM expects
|
|
/// the native token to be followed by string, whereas dart2js and DDC do not.
|
|
// TODO(sigmund, ahe): ideally we should remove the `native` syntax, if not,
|
|
// we should at least unify the VM and non-VM variants.
|
|
bool get nativeExtensionExpectsString => false;
|
|
|
|
/// Whether integer literals that cannot be represented exactly on the web
|
|
/// (i.e. in Javascript) should cause an error to be issued.
|
|
/// An example of such a number is `2^53 + 1` where in Javascript - because
|
|
/// integers are represented as doubles
|
|
/// `Math.pow(2, 53) = Math.pow(2, 53) + 1`.
|
|
bool get errorOnUnexactWebIntLiterals => false;
|
|
|
|
/// Whether set literals are natively supported by this target. If set
|
|
/// literals are not supported by the target, they will be desugared into
|
|
/// explicit `Set` creation (for non-const set literals) or wrapped map
|
|
/// literals (for const set literals).
|
|
bool get supportsSetLiterals => true;
|
|
|
|
/// Bit mask of [LateLowering] values for the late lowerings that should
|
|
/// be performed by the CFE.
|
|
///
|
|
/// For the selected lowerings, late fields and variables are encoded using
|
|
/// fields, getter, setters etc. in a way that provide equivalent semantics.
|
|
/// See `pkg/kernel/nnbd_api.md` for details.
|
|
int get enabledLateLowerings;
|
|
|
|
/// Returns `true` if the CFE should lower a late field given it
|
|
/// [hasInitializer], [isFinal], and [isStatic].
|
|
///
|
|
/// This is determined by the [enabledLateLowerings] mask.
|
|
bool isLateFieldLoweringEnabled(
|
|
{required bool hasInitializer,
|
|
required bool isFinal,
|
|
required bool isStatic}) {
|
|
// ignore: unnecessary_null_comparison
|
|
assert(hasInitializer != null);
|
|
// ignore: unnecessary_null_comparison
|
|
assert(isFinal != null);
|
|
// ignore: unnecessary_null_comparison
|
|
assert(isStatic != null);
|
|
int mask = LateLowering.getFieldLowering(
|
|
hasInitializer: hasInitializer, isFinal: isFinal, isStatic: isStatic);
|
|
return enabledLateLowerings & mask != 0;
|
|
}
|
|
|
|
/// Returns `true` if the CFE should lower a late local variable given it
|
|
/// [hasInitializer], [isFinal], and its type [isPotentiallyNullable].
|
|
///
|
|
/// This is determined by the [enabledLateLowerings] mask.
|
|
bool isLateLocalLoweringEnabled(
|
|
{required bool hasInitializer,
|
|
required bool isFinal,
|
|
required bool isPotentiallyNullable}) {
|
|
// ignore: unnecessary_null_comparison
|
|
assert(hasInitializer != null);
|
|
// ignore: unnecessary_null_comparison
|
|
assert(isFinal != null);
|
|
// ignore: unnecessary_null_comparison
|
|
assert(isPotentiallyNullable != null);
|
|
int mask = LateLowering.getLocalLowering(
|
|
hasInitializer: hasInitializer,
|
|
isFinal: isFinal,
|
|
isPotentiallyNullable: isPotentiallyNullable);
|
|
return enabledLateLowerings & mask != 0;
|
|
}
|
|
|
|
/// If `true`, the backend supports creation and checking of a sentinel value
|
|
/// for uninitialized late fields and variables through the `createSentinel`
|
|
/// and `isSentinel` methods in `dart:_internal`.
|
|
///
|
|
/// If `true` this is used when [supportsLateFields] is `false`.
|
|
bool get supportsLateLoweringSentinel;
|
|
|
|
/// Whether static fields with initializers in nnbd libraries should be
|
|
/// encoded using the late field lowering.
|
|
bool get useStaticFieldLowering;
|
|
|
|
/// Whether calls to getters and fields should be encoded as a .call
|
|
/// invocation on a property get.
|
|
///
|
|
/// If `false`, calls to getters and fields are encoded as method invocations
|
|
/// with the accessed getter or field as the interface target.
|
|
bool get supportsExplicitGetterCalls;
|
|
|
|
bool get supportsNewMethodInvocationEncoding;
|
|
|
|
/// Builds an expression that instantiates an [Invocation] that can be passed
|
|
/// to [noSuchMethod].
|
|
Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,
|
|
String name, Arguments arguments, int offset, bool isSuper);
|
|
|
|
Expression instantiateNoSuchMethodError(CoreTypes coreTypes,
|
|
Expression receiver, String name, Arguments arguments, int offset,
|
|
{bool isMethod: false,
|
|
bool isGetter: false,
|
|
bool isSetter: false,
|
|
bool isField: false,
|
|
bool isLocalVariable: false,
|
|
bool isDynamic: false,
|
|
bool isSuper: false,
|
|
bool isStatic: false,
|
|
bool isConstructor: false,
|
|
bool isTopLevel: false});
|
|
|
|
/// Configure the given [Component] in a target specific way.
|
|
/// Returns the configured component.
|
|
Component configureComponent(Component component) => component;
|
|
|
|
// Configure environment defines in a target-specific way.
|
|
Map<String, String> updateEnvironmentDefines(Map<String, String> map) => map;
|
|
|
|
String toString() => 'Target($name)';
|
|
|
|
Class? concreteListLiteralClass(CoreTypes coreTypes) => null;
|
|
Class? concreteConstListLiteralClass(CoreTypes coreTypes) => null;
|
|
|
|
Class? concreteMapLiteralClass(CoreTypes coreTypes) => null;
|
|
Class? concreteConstMapLiteralClass(CoreTypes coreTypes) => null;
|
|
|
|
Class? concreteIntLiteralClass(CoreTypes coreTypes, int value) => null;
|
|
Class? concreteDoubleLiteralClass(CoreTypes coreTypes, double value) => null;
|
|
Class? concreteStringLiteralClass(CoreTypes coreTypes, String value) => null;
|
|
|
|
ConstantsBackend constantsBackend(CoreTypes coreTypes);
|
|
}
|
|
|
|
class NoneConstantsBackend extends ConstantsBackend {
|
|
@override
|
|
final bool supportsUnevaluatedConstants;
|
|
|
|
const NoneConstantsBackend({required this.supportsUnevaluatedConstants});
|
|
}
|
|
|
|
class NoneTarget extends Target {
|
|
final TargetFlags flags;
|
|
|
|
NoneTarget(this.flags);
|
|
|
|
@override
|
|
int get enabledLateLowerings => flags.forceLateLoweringsForTesting;
|
|
|
|
@override
|
|
bool get supportsLateLoweringSentinel =>
|
|
flags.forceLateLoweringSentinelForTesting;
|
|
|
|
@override
|
|
bool get useStaticFieldLowering => flags.forceStaticFieldLoweringForTesting;
|
|
|
|
@override
|
|
bool get supportsExplicitGetterCalls =>
|
|
!flags.forceNoExplicitGetterCallsForTesting;
|
|
|
|
@override
|
|
bool get supportsNewMethodInvocationEncoding => true;
|
|
|
|
@override
|
|
String get name => 'none';
|
|
|
|
@override
|
|
List<String> get extraRequiredLibraries => <String>[];
|
|
|
|
@override
|
|
void performModularTransformationsOnLibraries(
|
|
Component component,
|
|
CoreTypes coreTypes,
|
|
ClassHierarchy hierarchy,
|
|
List<Library> libraries,
|
|
Map<String, String> environmentDefines,
|
|
DiagnosticReporter diagnosticReporter,
|
|
ReferenceFromIndex referenceFromIndex,
|
|
{void Function(String msg)? logger,
|
|
ChangedStructureNotifier? changedStructureNotifier}) {}
|
|
|
|
@override
|
|
Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,
|
|
String name, Arguments arguments, int offset, bool isSuper) {
|
|
return new InvalidExpression(null);
|
|
}
|
|
|
|
@override
|
|
Expression instantiateNoSuchMethodError(CoreTypes coreTypes,
|
|
Expression receiver, String name, Arguments arguments, int offset,
|
|
{bool isMethod: false,
|
|
bool isGetter: false,
|
|
bool isSetter: false,
|
|
bool isField: false,
|
|
bool isLocalVariable: false,
|
|
bool isDynamic: false,
|
|
bool isSuper: false,
|
|
bool isStatic: false,
|
|
bool isConstructor: false,
|
|
bool isTopLevel: false}) {
|
|
return new InvalidExpression(null);
|
|
}
|
|
|
|
@override
|
|
ConstantsBackend constantsBackend(CoreTypes coreTypes) =>
|
|
// TODO(johnniwinther): Should this vary with the use case?
|
|
const NoneConstantsBackend(supportsUnevaluatedConstants: true);
|
|
}
|
|
|
|
class LateLowering {
|
|
static const int nullableUninitializedNonFinalLocal = 1 << 0;
|
|
static const int nonNullableUninitializedNonFinalLocal = 1 << 1;
|
|
static const int nullableUninitializedFinalLocal = 1 << 2;
|
|
static const int nonNullableUninitializedFinalLocal = 1 << 3;
|
|
static const int nullableInitializedNonFinalLocal = 1 << 4;
|
|
static const int nonNullableInitializedNonFinalLocal = 1 << 5;
|
|
static const int nullableInitializedFinalLocal = 1 << 6;
|
|
static const int nonNullableInitializedFinalLocal = 1 << 7;
|
|
static const int uninitializedNonFinalStaticField = 1 << 8;
|
|
static const int uninitializedFinalStaticField = 1 << 9;
|
|
static const int initializedNonFinalStaticField = 1 << 10;
|
|
static const int initializedFinalStaticField = 1 << 11;
|
|
static const int uninitializedNonFinalInstanceField = 1 << 12;
|
|
static const int uninitializedFinalInstanceField = 1 << 13;
|
|
static const int initializedNonFinalInstanceField = 1 << 14;
|
|
static const int initializedFinalInstanceField = 1 << 15;
|
|
|
|
static const int none = 0;
|
|
static const int all = (1 << 16) - 1;
|
|
|
|
static int getLocalLowering(
|
|
{required bool hasInitializer,
|
|
required bool isFinal,
|
|
required bool isPotentiallyNullable}) {
|
|
// ignore: unnecessary_null_comparison
|
|
assert(hasInitializer != null);
|
|
// ignore: unnecessary_null_comparison
|
|
assert(isFinal != null);
|
|
// ignore: unnecessary_null_comparison
|
|
assert(isPotentiallyNullable != null);
|
|
if (hasInitializer) {
|
|
if (isFinal) {
|
|
if (isPotentiallyNullable) {
|
|
return nullableInitializedFinalLocal;
|
|
} else {
|
|
return nonNullableInitializedFinalLocal;
|
|
}
|
|
} else {
|
|
if (isPotentiallyNullable) {
|
|
return nullableInitializedNonFinalLocal;
|
|
} else {
|
|
return nonNullableInitializedNonFinalLocal;
|
|
}
|
|
}
|
|
} else {
|
|
if (isFinal) {
|
|
if (isPotentiallyNullable) {
|
|
return nullableUninitializedFinalLocal;
|
|
} else {
|
|
return nonNullableUninitializedFinalLocal;
|
|
}
|
|
} else {
|
|
if (isPotentiallyNullable) {
|
|
return nullableUninitializedNonFinalLocal;
|
|
} else {
|
|
return nonNullableUninitializedNonFinalLocal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int getFieldLowering(
|
|
{required bool hasInitializer,
|
|
required bool isFinal,
|
|
required bool isStatic}) {
|
|
// ignore: unnecessary_null_comparison
|
|
assert(hasInitializer != null);
|
|
// ignore: unnecessary_null_comparison
|
|
assert(isFinal != null);
|
|
// ignore: unnecessary_null_comparison
|
|
assert(isStatic != null);
|
|
if (hasInitializer) {
|
|
if (isFinal) {
|
|
if (isStatic) {
|
|
return initializedFinalStaticField;
|
|
} else {
|
|
return initializedFinalInstanceField;
|
|
}
|
|
} else {
|
|
if (isStatic) {
|
|
return initializedNonFinalStaticField;
|
|
} else {
|
|
return initializedNonFinalInstanceField;
|
|
}
|
|
}
|
|
} else {
|
|
if (isFinal) {
|
|
if (isStatic) {
|
|
return uninitializedFinalStaticField;
|
|
} else {
|
|
return uninitializedFinalInstanceField;
|
|
}
|
|
} else {
|
|
if (isStatic) {
|
|
return uninitializedNonFinalStaticField;
|
|
} else {
|
|
return uninitializedNonFinalInstanceField;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|