getRuntimeType method

RuntimeType? getRuntimeType(
  1. Object? value
)

Implementation

RuntimeType? getRuntimeType(Object? value) {
  if (value is InterpretedInstance) {
    return value.klass; // InterpretedClass is a RuntimeType
  }
  if (value is BridgedInstance) {
    return value.bridgedClass; // BridgedClass is a RuntimeType
  }
  // G-DOV2-7 FIX: Handle InterpretedEnumValue - return its parent enum as the type
  if (value is InterpretedEnumValue) {
    return value.parentEnum; // InterpretedEnum is a RuntimeType
  }
  // Bucket #4 fix: Handle BridgedEnumValue so extension lookups against the
  // enum's parent BridgedEnum can succeed (e.g. WidgetStateOperators on a
  // WidgetState value).
  if (value is BridgedEnumValue) {
    return value.enumType;
  }
  // Handle Dart primitive/core types by looking them up in the environment
  // Assumes core types (String, int, bool, List, Map, etc.) are registered as BridgedClass
  String? typeName;
  if (value == null) typeName = 'Null';
  if (value is String) typeName = 'String';
  if (value is int) typeName = 'int';
  if (value is double) typeName = 'double';
  if (value is bool) typeName = 'bool';
  if (value is List) typeName = 'List';
  if (value is Map) typeName = 'Map';

  if (typeName != null) {
    // Cluster C26 FIX: For List/Map, prefer a more-specific bridged class
    // (e.g. Uint8List, Int32List) registered for the actual runtime type.
    // `value is List` matches typed-data subclasses, which previously
    // collapsed their runtime type to plain `List` and broke return-type
    // checks on functions declared to return `Uint8List` and friends.
    // If `toBridgedClass` resolves to a more specific bridge, return it;
    // otherwise fall through to the generic lookup below.
    if (value != null && (typeName == 'List' || typeName == 'Map')) {
      try {
        final specific = toBridgedClass(value.runtimeType);
        if (specific.name != typeName) {
          return specific;
        }
      } on RuntimeD4rtException {
        // No specific bridge — fall through to generic typeName lookup.
      }
    }
    try {
      final typeObj = get(typeName); // Look up the type name
      if (typeObj is RuntimeType) {
        return typeObj;
      } else {
        Logger.warn(
          "[getRuntimeType] Found symbol '$typeName' but it's not a RuntimeType (${typeObj?.runtimeType})",
        );
      }
    } on RuntimeD4rtException {
      Logger.warn(
        "[getRuntimeType] RuntimeType for primitive '$typeName' not found in environment.",
      );
    }
  }

  // For other native objects (e.g., DateTime, Duration, etc.), try to find their BridgedClass
  if (value != null) {
    try {
      final bridgedClass = toBridgedClass(value.runtimeType);
      return bridgedClass;
    } on RuntimeD4rtException {
      // No bridged class found for this type
      Logger.debug(
        "[getRuntimeType] No BridgedClass found for native type ${value.runtimeType}",
      );
    }
    // C20a fix: When the runtime type isn't a registered bridge (e.g.
    // private impl types returned by extension operators like
    // `WidgetState.a | WidgetState.b` returning a `_WidgetStateOr`),
    // fall back to `isAssignable` iteration so we can recover the
    // bridged interface (e.g. `WidgetStatesConstraint`) it implements.
    // This lets subsequent operator dispatch (e.g. `& ~WidgetState.x`
    // applied to the OR result) reach the right extension.
    Environment? current = this;
    BridgedClass? bestMatch;
    while (current != null) {
      for (final entry in current._bridgedClassesLookupByType.entries) {
        final bridge = entry.value;
        if (bridge.isAssignable != null && bridge.isAssignable!(value)) {
          bestMatch = bridge;
        }
      }
      current = current._enclosing;
    }
    if (bestMatch != null) {
      Logger.debug(
        "[getRuntimeType] Resolved native ${value.runtimeType} via "
        "isAssignable to BridgedClass(${bestMatch.name})",
      );
      return bestMatch;
    }
  }

  return null; // Type couldn't be determined
}