visitPrefixedIdentifier method

  1. @override
Object? visitPrefixedIdentifier(
  1. SPrefixedIdentifier node
)
override

Implementation

@override
Object? visitPrefixedIdentifier(SPrefixedIdentifier node) {
  final prefixValue = node.prefix!.accept<Object?>(this);
  if (prefixValue is AsyncSuspensionRequest) {
    // Propagate the suspension so that the state machine resumes this node after resolution
    return prefixValue;
  }
  final memberName = node.identifier!.name;

  // Handle the case where the prefix is an environment (prefixed import)
  if (prefixValue is Environment) {
    Logger.debug(
      "[SPrefixedIdentifier] The prefix '${node.prefix.toString()}' resolved to an Environment. Searching for '$memberName' in this environment.",
    );
    try {
      // The call to get() on the prefixed environment could return a function (which must be called if it's a getter)
      // or a direct value.
      final member = prefixValue.get(memberName);
      // If it's an InterpretedFunction and a getter, it must be called.
      if (member is InterpretedFunction && member.isGetter) {
        Logger.debug(
          "[SPrefixedIdentifier] Member '$memberName' is a getter. Calling...",
        );
        return member.call(
          this,
          [],
          {},
        ); // Call without 'this' because it's a prefixed import
      }
      Logger.debug(
        "[SPrefixedIdentifier] Member '$memberName' found directly: $member",
      );
      return member; // Return the value/function directly
    } on RuntimeD4rtException catch (e) {
      throw RuntimeD4rtException(
        "Erreur lors de la récupération du membre '$memberName' de l'import préfixé '${node.prefix.toString()}': ${e.message}",
      );
    }
  }

  if (prefixValue is InterpretedClass) {
    // Static access
    try {
      return prefixValue.getStaticField(memberName);
    } on RuntimeD4rtException catch (_) {
      InterpretedFunction? staticMember = prefixValue.findStaticGetter(
        memberName,
      );
      staticMember ??= prefixValue.findStaticMethod(memberName);
      if (staticMember != null) {
        if (staticMember.isGetter) {
          return staticMember.call(this, [], {});
        } else {
          return staticMember;
        }
      } else {
        // G-DOV-5 FIX: Handle constructor tear-offs (Class.new)
        // Return the class itself as it implements Callable and its call()
        // method properly creates an instance and calls the constructor.
        if (memberName == 'new') {
          final constructor = prefixValue.findConstructor('');
          if (constructor != null) return prefixValue;
        }
        // G-DOV2-2 FIX: Handle named constructor tear-offs (Class.fromMap, etc.)
        // Named constructors can be used as tear-offs when passed to higher-order functions
        final namedConstructor = prefixValue.findConstructor(memberName);
        if (namedConstructor != null) {
          // Return a callable that will invoke this named constructor
          return _NamedConstructorTearOff(
            prefixValue,
            namedConstructor,
            memberName,
          );
        }
        // Cluster C33: class-as-value (Type literal) semantics. A
        // PrefixedIdentifier like `slotType.hashCode` where `slotType`
        // is bound to an InterpretedClass should dispatch
        // `Object.hashCode`/`Object.runtimeType` on the Type instance,
        // not look up a static member. Fall back before throwing.
        if (memberName == 'hashCode') {
          return prefixValue.hashCode;
        }
        if (memberName == 'runtimeType') {
          return prefixValue.runtimeType;
        }
        throw RuntimeD4rtException(
          "Undefined static member '$memberName' on class '${prefixValue.name}'.",
        );
      }
    }
  } else if (prefixValue is InterpretedEnum) {
    if (memberName == 'values') {
      Logger.debug(
        "[SPrefixedIdentifier] Accessing static getter 'values' on enum '${prefixValue.name}'.",
      );
      return prefixValue.valuesList;
    }

    // Check enum values first
    final value = prefixValue.values[memberName];
    if (value != null) {
      Logger.debug(
        "[SPrefixedIdentifier] Accessing enum value '$memberName' on enum '${prefixValue.name}'.",
      );
      return value;
    }

    // Check static fields
    if (prefixValue.staticFields.containsKey(memberName)) {
      Logger.debug(
        "[SPrefixedIdentifier] Accessing static field '$memberName' on enum '${prefixValue.name}'.",
      );
      return prefixValue.staticFields[memberName];
    }

    // Check static getters
    final staticGetter = prefixValue.staticGetters[memberName];
    if (staticGetter != null) {
      Logger.debug(
        "[SPrefixedIdentifier] Calling static getter '$memberName' on enum '${prefixValue.name}'.",
      );
      return staticGetter.call(this, [], {});
    }

    // Check static methods
    final staticMethod = prefixValue.staticMethods[memberName];
    if (staticMethod != null) {
      Logger.debug(
        "[SPrefixedIdentifier] Accessing static method '$memberName' on enum '${prefixValue.name}'.",
      );
      return staticMethod;
    }

    // Check mixins for static members (reverse order)
    for (final mixin in prefixValue.mixins.reversed) {
      // Check static fields
      try {
        final mixinStaticField = mixin.getStaticField(memberName);
        Logger.debug(
          "[SPrefixedIdentifier] Found static field '$memberName' from mixin '${mixin.name}' for enum '${prefixValue.name}'",
        );
        return mixinStaticField;
      } on RuntimeD4rtException {
        // Continue to next check
      }

      // Check static getters
      final mixinStaticGetter = mixin.findStaticGetter(memberName);
      if (mixinStaticGetter != null) {
        Logger.debug(
          "[SPrefixedIdentifier] Found static getter '$memberName' from mixin '${mixin.name}' for enum '${prefixValue.name}'",
        );
        return mixinStaticGetter.call(this, [], {});
      }

      // Check static methods
      final mixinStaticMethod = mixin.findStaticMethod(memberName);
      if (mixinStaticMethod != null) {
        Logger.debug(
          "[SPrefixedIdentifier] Found static method '$memberName' from mixin '${mixin.name}' for enum '${prefixValue.name}'",
        );
        return mixinStaticMethod;
      }
    }

    // Not found
    throw RuntimeD4rtException(
      "Undefined static member '$memberName' on enum '${prefixValue.name}'. Available enum values: ${prefixValue.valueNames.join(', ')}",
    );
  } else if (prefixValue is BridgedClass) {
    final bridgedClass = prefixValue;
    Logger.debug(
      "[SPrefixedIdentifier] Static access on BridgedClass: ${bridgedClass.name}.$memberName",
    );
    final staticGetter = bridgedClass.findStaticGetterAdapter(memberName);
    if (staticGetter != null) {
      return wrapNativeReturnValue(staticGetter(this));
    }
    final staticMethod = bridgedClass.findStaticMethodAdapter(memberName);
    if (staticMethod != null) {
      // Return the static method as a callable value
      Logger.debug(
        "[SPrefixedIdentifier] Returning bridged static method '$memberName' as value from '${bridgedClass.name}'.",
      );
      return BridgedStaticMethodCallable(
        bridgedClass,
        staticMethod,
        memberName,
      );
    }
    // Constructor tear-off support for bridged classes:
    //   `EagerGestureRecognizer.new`            → unnamed-ctor tear-off
    //   `Foo.fromMap`                           → named-ctor tear-off
    // Mirrors the InterpretedClass branch above. Without this, scripts
    // using Dart 2.15+ tear-off syntax against a bridged class fail with
    // "Undefined static member 'new' on bridged class '...'".
    if (memberName == 'new') {
      final ctor = bridgedClass.findConstructorAdapter('');
      if (ctor != null) {
        Logger.debug(
          "[SPrefixedIdentifier] Returning bridged unnamed-constructor tear-off '${bridgedClass.name}.new'.",
        );
        return _BridgedConstructorTearOff(bridgedClass, ctor, '');
      }
    }
    final namedCtor = bridgedClass.findConstructorAdapter(memberName);
    if (namedCtor != null) {
      Logger.debug(
        "[SPrefixedIdentifier] Returning bridged named-constructor tear-off '${bridgedClass.name}.$memberName'.",
      );
      return _BridgedConstructorTearOff(bridgedClass, namedCtor, memberName);
    }
    // Cluster C32: class-as-value (Type literal) semantics. A
    // PrefixedIdentifier like `slotType.hashCode` where `slotType` is
    // bound to a BridgedClass should dispatch
    // `Object.hashCode`/`Object.runtimeType` on the Type instance, not
    // look up a static member. Fall back before throwing.
    if (memberName == 'hashCode') {
      return bridgedClass.hashCode;
    }
    if (memberName == 'runtimeType') {
      return bridgedClass.runtimeType;
    }
    throw RuntimeD4rtException(
      "Undefined static member '$memberName' on bridged class '${bridgedClass.name}'.",
    );
  } else if (prefixValue is InterpretedExtension) {
    // Handle static member access on extensions
    final extension = prefixValue;
    Logger.debug(
      "[SPrefixedIdentifier] Static access on Extension: ${extension.name ?? '<unnamed>'}.$memberName",
    );

    // Check static field
    if (extension.staticFields.containsKey(memberName)) {
      return extension.staticFields[memberName];
    }

    // Check static getter
    final staticGetter = extension.findStaticGetter(memberName);
    if (staticGetter != null) {
      return staticGetter.call(this, [], {});
    }

    // Check static method
    final staticMethod = extension.findStaticMethod(memberName);
    if (staticMethod != null) {
      return staticMethod;
    }

    throw RuntimeD4rtException(
      "Undefined static member '$memberName' on extension '${extension.name ?? '<unnamed>'}'.",
    );
  } else if (prefixValue is InterpretedInstance) {
    try {
      final member = prefixValue.get(memberName, visitor: this);
      if (member is InterpretedFunction && member.isGetter) {
        return member.bind(prefixValue).call(this, [], {});
      } else {
        return member;
      }
    } on RuntimeD4rtException catch (e) {
      if (e.message.contains("Undefined property '$memberName'")) {
        final extensionMember = environment.findExtensionMember(
          prefixValue,
          memberName,
        );
        if (extensionMember is ExtensionMemberCallable) {
          if (extensionMember.isGetter) {
            return extensionMember.call(this, [prefixValue], {});
          } else if (!extensionMember.isOperator &&
              !extensionMember.isSetter) {
            return extensionMember;
          }
        }
      }
      throw RuntimeD4rtException(
        "${e.message} (accessing property via SPrefixedIdentifier '$memberName')",
      );
    }
  } else if (prefixValue is InterpretedEnumValue) {
    if (memberName == 'index') {
      Logger.debug(
        "[SPrefixedIdentifier] Accessing getter 'index' on enum value '$prefixValue'.",
      );
      return prefixValue.index;
    } else if (memberName == 'toString') {
      Logger.debug(
        "[SPrefixedIdentifier] Accessing method 'toString' on enum value '$prefixValue'. Returning callable.",
      );
      // Return directly the string for simplicity in prefixed access?
      // No, return a callable function to be consistent with methods.
      return NativeFunction(
        (_, args, _, _) {
          if (args.isNotEmpty) {
            throw RuntimeD4rtException("toString() takes no arguments.");
          }
          return prefixValue.toString();
        },
        arity: 0,
        name: 'toString',
      );
    } else if (memberName == 'name') {
      Logger.debug(
        "[SPrefixedIdentifier] Explicitly accessing 'name' on enum value '$prefixValue'. Returning value.",
      );
      return prefixValue.name; // Access directly the 'name' property
    } else {
      Logger.debug(
        "[SPrefixedIdentifier] Accessing member '$memberName' on enum value '$prefixValue'. Calling get()...",
      );
      try {
        // Pass 'this' (the visitor) to allow getter execution if needed.
        return prefixValue.get(memberName, this);
      } on ReturnException catch (e) {
        // If get() executes a getter that throws ReturnException
        return e.value;
      } on RuntimeD4rtException catch (e) {
        // G-DOV2-7 FIX: Try extension lookup if direct access fails
        if (e.message.contains("Undefined property '$memberName'")) {
          Logger.debug(
            "[SPrefixedIdentifier] Direct access failed for '$memberName' on enum $prefixValue. Trying extension lookup...",
          );
          final extensionMember = environment.findExtensionMember(
            prefixValue,
            memberName,
          );
          if (extensionMember is ExtensionMemberCallable) {
            if (extensionMember.isGetter) {
              Logger.debug(
                "[SPrefixedIdentifier] Found extension getter '$memberName' for enum. Calling...",
              );
              return extensionMember.call(this, [prefixValue], {});
            } else if (!extensionMember.isOperator &&
                !extensionMember.isSetter) {
              Logger.debug(
                "[SPrefixedIdentifier] Found extension method '$memberName' for enum. Returning tear-off.",
              );
              return extensionMember;
            }
          }
        }
        // Propagate error if extension lookup failed
        throw RuntimeD4rtException(
          "Error getting member '$memberName' from enum value '$prefixValue': ${e.message}",
        );
      } catch (e) {
        // Propagate other errors from get()
        throw RuntimeD4rtException(
          "Error getting member '$memberName' from enum value '$prefixValue': $e",
        );
      }
    }
  } else if (toBridgedInstance(prefixValue).$2) {
    final bridgedInstance = toBridgedInstance(prefixValue).$1!;
    // GEN-075: Check universal Object properties first
    switch (memberName) {
      case 'hashCode':
        return bridgedInstance.nativeObject.hashCode;
      case 'runtimeType':
        return bridgedInstance.nativeObject.runtimeType;
      default:
    }
    final getterAdapter = bridgedInstance.bridgedClass
        .findInstanceGetterAdapter(memberName);
    if (getterAdapter != null) {
      return getterAdapter(this, bridgedInstance.nativeObject);
    }
    final methodAdapter = bridgedInstance.bridgedClass
        .findInstanceMethodAdapter(memberName);
    if (methodAdapter != null) {
      // C20a fix: prefixed identifier `prefix.method` is a method tear-off
      // when not followed by an invocation. Return the callable rather than
      // invoking it with empty arguments. The previous `.call(this, [], {})`
      // crashed bridges that index `positionalArgs[0]` (e.g. Set.contains
      // used as `_kAllStates.where(states.contains)`), surfacing as
      // "Set.contains: Invalid value" RangeError.
      return BridgedMethodCallable(
        bridgedInstance,
        methodAdapter,
        memberName,
      );
    }

    // Cluster-12 (priority 3): Walk the registered supertype chain when
    // the leaf bridge has no matching getter/method. See
    // [InterpreterVisitorExtension.lookupOnBridgedSupertypes].
    final supertypeMatch =
        lookupOnBridgedSupertypes(bridgedInstance, memberName);
    if (supertypeMatch.$2) {
      Logger.debug(
        "[SPrefixedIdentifier]   Resolved '$memberName' via supertype walk on '${bridgedInstance.bridgedClass.name}'.",
      );
      return supertypeMatch.$1;
    }

    // No adapter found, try extension methods/getters
    try {
      final extensionMember = environment.findExtensionMember(
        bridgedInstance,
        memberName,
      );
      if (extensionMember is ExtensionMemberCallable) {
        if (extensionMember.isGetter) {
          Logger.debug(
            "[SPrefixedIdentifier] Found extension getter '$memberName' for ${bridgedInstance.bridgedClass.name}. Calling...",
          );
          final extensionArgs = <Object?>[bridgedInstance];
          return extensionMember.call(this, extensionArgs, {});
        } else if (!extensionMember.isOperator && !extensionMember.isSetter) {
          Logger.debug(
            "[SPrefixedIdentifier] Found extension method '$memberName' for ${bridgedInstance.bridgedClass.name}. Returning callable.",
          );
          return BoundExtensionCallable(bridgedInstance, extensionMember);
        }
      }
    } on RuntimeD4rtException catch (findError) {
      Logger.debug(
        "[SPrefixedIdentifier] Error finding extension '$memberName' for ${bridgedInstance.bridgedClass.name}: ${findError.message}",
      );
    }

    // RC-5: Enum property fallback — same as visitSPropertyAccess Fix I
    if (bridgedInstance.nativeObject is Enum) {
      final enumObj = bridgedInstance.nativeObject as Enum;
      switch (memberName) {
        case 'name':
          return enumObj.name;
        case 'index':
          return enumObj.index;
        case 'hashCode':
          return enumObj.hashCode;
        case 'runtimeType':
          return enumObj.runtimeType;
        case 'toString':
          return NativeFunction(
            (visitor, args, namedArgs, typeArgs) => enumObj.toString(),
            arity: 0,
            name: 'toString',
          );
      }
      // Cluster-26 (Key.label dispatch): If a custom getter was registered
      // on the BridgedEnumDefinition (e.g. KeyEventType.label), dispatch
      // through the BridgedEnumValue. Only entered for unknown properties
      // to keep built-in enum access on the fast path.
      // Walks the current scope chain (which extends from the per-module
      // env where bridges register the BridgedEnum). Falls back to the
      // global env for runners that pre-populate enums there.
      final bridgedEnumValue =
          environment.getBridgedEnumValue(enumObj) ??
          globalEnvironment.getBridgedEnumValue(enumObj);
      if (bridgedEnumValue != null) {
        try {
          return bridgedEnumValue.get(memberName);
        } on RuntimeD4rtException {
          // Fall through to the "Undefined property" error below.
        }
      }
    }

    // D2: D4InterpretedProxy unwrap fallback (see visitSPropertyAccess).
    final nativeForUnwrap = bridgedInstance.nativeObject;
    if (nativeForUnwrap is D4InterpretedProxy) {
      final inner = nativeForUnwrap.d4rtInstance;
      if (inner is InterpretedInstance) {
        try {
          return inner.get(memberName, visitor: this);
        } catch (_) {
          // Fall through to the "Undefined property" error below.
        }
      }
    }

    throw RuntimeD4rtException(
      "Undefined property or method '$memberName' on bridged instance of '${bridgedInstance.bridgedClass.name}'.",
    );
  } else if (prefixValue is InterpretedRecord) {
    // Accessing field of a record
    final record = prefixValue;
    Logger.debug(
      "[SPrefixedIdentifier] Access on InterpretedRecord: .$memberName",
    );

    // Check for Object methods (hashCode, runtimeType, toString)
    switch (memberName) {
      case 'hashCode':
        return record.hashCode;
      case 'runtimeType':
        return record.runtimeType;
    }

    // Check if it's a positional field access ($1, $2, ...)
    if (memberName.startsWith('\$') && memberName.length > 1) {
      try {
        final index = int.parse(memberName.substring(1)) - 1;
        if (index >= 0 && index < record.positionalFields.length) {
          return record.positionalFields[index];
        } else {
          throw RuntimeD4rtException(
            "Record positional field index \$$index out of bounds (0..${record.positionalFields.length - 1}).",
          );
        }
      } catch (e) {
        // Handle parse errors or other issues
        throw RuntimeD4rtException(
          "Invalid positional record field accessor '$memberName'.",
        );
      }
    } else {
      // Check if it's a named field access
      if (record.namedFields.containsKey(memberName)) {
        return record.namedFields[memberName];
      } else {
        throw RuntimeD4rtException(
          "Record has no field named '$memberName'. Available fields: ${record.namedFields.keys.join(', ')}",
        );
      }
    }
  } else if (prefixValue is Record) {
    // E6: native Dart Record (e.g., produced by `Iterable.indexed` from
    // dart:core). Records do not implement reflection without
    // `dart:mirrors`, so we route positional access via `dynamic`
    // dispatch ($1..$9) and Object members directly.
    return _accessNativeRecordField(prefixValue, memberName);
  } else if (prefixValue is InterpretedExtensionTypeInstance) {
    // Lim-1 FIX: Handle property access on extension type instances
    final extensionInstance = prefixValue;
    Logger.debug(
      "[SPrefixedIdentifier] Access on InterpretedExtensionTypeInstance: .$memberName",
    );

    // Check for Object methods first (hashCode, runtimeType, toString)
    switch (memberName) {
      case 'hashCode':
        return extensionInstance.representationValue.hashCode;
      case 'runtimeType':
        return extensionInstance.extensionType;
    }

    // Delegate to the extension type instance's get() method
    try {
      return extensionInstance.get(memberName, this);
    } on ReturnException catch (e) {
      // If get() executes a getter that throws ReturnException
      return e.value;
    }
  } else if (prefixValue is BridgedEnum) {
    Logger.debug(
      "[SPrefixedIdentifier] Accessing value on BridgedEnum: ${prefixValue.name}.$memberName",
    );
    final enumValue = prefixValue.getValue(memberName);
    if (enumValue != null) {
      return enumValue; // Return the BridgedEnumValue
    } else {
      throw RuntimeD4rtException(
        "Undefined enum value '$memberName' on bridged enum '${prefixValue.name}'.",
      );
    }
  } else if (prefixValue is BridgedEnumValue) {
    final bridgedEnumValue = prefixValue;
    Logger.debug(
      "[SPrefixedIdentifier] Accessing property '$memberName' on BridgedEnumValue (within InterpretedEnumValue block): $bridgedEnumValue",
    );
    try {
      // Use the get() method of BridgedEnumValue
      return bridgedEnumValue.get(memberName);
    } on ReturnException catch (e) {
      return e.value;
    } on RuntimeD4rtException {
      // Relaunch the RuntimeErrors directly
      rethrow;
    } catch (e, s) {
      // Catch other potential errors (ex: from the adapter)
      Logger.error(
        "[SPrefixedIdentifier] Native exception during bridged enum property get '$bridgedEnumValue.$memberName': $e\n$s",
      );
      throw RuntimeD4rtException(
        "Native error during bridged enum property get '$memberName' on $bridgedEnumValue: $e",
        originalException: e,
      );
    }
  } else if (prefixValue is Callable) {
    // Handle property access on function types (InterpretedFunction, NativeFunction, etc.)
    Logger.debug("[SPrefixedIdentifier] Access on Callable: .$memberName");
    switch (memberName) {
      case 'hashCode':
        return prefixValue.hashCode;
      case 'runtimeType':
        // Return Function as the runtimeType for all callable types
        return Function;
      case 'toString':
        return NativeFunction(
          (_, args, _, _) {
            if (args.isNotEmpty) {
              throw RuntimeD4rtException("toString() takes no arguments.");
            }
            return prefixValue.toString();
          },
          arity: 0,
          name: 'toString',
        );
    }
    throw RuntimeD4rtException(
      "Cannot access property '$memberName' on function. Functions only support 'hashCode', 'runtimeType', and 'toString'.",
    );
  } else {
    try {
      final extensionMember = environment.findExtensionMember(
        prefixValue,
        memberName,
      );

      if (extensionMember is ExtensionMemberCallable) {
        // Handle extension getter call immediately
        if (extensionMember.isGetter) {
          Logger.debug(
            "[SPrefixedIdentifier] Found extension getter '$memberName' (fallback). Calling...",
          );
          final extensionPositionalArgs = [
            prefixValue,
          ]; // Getter takes receiver
          return extensionMember.call(this, extensionPositionalArgs, {});
        } else if (!extensionMember.isOperator && !extensionMember.isSetter) {
          // Return extension method itself if it's not a getter/setter/operator
          Logger.debug(
            "[SPrefixedIdentifier] Found extension method '$memberName' (fallback). Returning callable.",
          );
          return extensionMember;
        }
        // If it's an operator or setter, we probably shouldn't reach here via SPrefixedIdentifier
        // Fall through to Stdlib if it wasn't a getter or regular method.
      }
      // If no suitable extension found, proceed to Stdlib call
      Logger.debug(
        "[SPrefixedIdentifier] No suitable extension found for '$memberName' (fallback). Trying Stdlib...",
      );
    } on RuntimeD4rtException catch (findError) {
      // If findExtensionMember itself threw (e.g., type not found), proceed to Stdlib
      Logger.debug(
        "[SPrefixedIdentifier] Error finding extension '$memberName' (fallback): ${findError.message}. Trying Stdlib...",
      );
    }

    // Fix I: Generic Enum property getter — handles raw native enums
    // not wrapped in BridgedEnumValue (e.g., returned by bridge getters).
    // All Dart enums implement the Enum interface with .name and .index.
    if (prefixValue is Enum) {
      switch (memberName) {
        case 'name':
          return (prefixValue).name;
        case 'index':
          return (prefixValue).index;
        case 'hashCode':
          return prefixValue.hashCode;
        case 'runtimeType':
          return prefixValue.runtimeType;
        case 'toString':
          return NativeFunction(
            (_, args, _, _) => prefixValue.toString(),
            arity: 0,
            name: 'toString',
          );
      }
    }

    // GEN-C3c: Universal Object-member fallback for arbitrary native
    // targets reached via PrefixedIdentifier. Every Dart Object exposes
    // `toString`, `hashCode`, and `runtimeType`; these must always
    // resolve. Mirrors the BridgedInstance branch (GEN-075) above and
    // the same fallback in visitPropertyAccess.
    if (prefixValue != null) {
      switch (memberName) {
        case 'hashCode':
          return prefixValue.hashCode;
        case 'runtimeType':
          return prefixValue.runtimeType;
        case 'toString':
          return NativeFunction(
            (_, args, _, _) => prefixValue.toString(),
            arity: 0,
            name: 'toString',
          );
      }
    }

    throw RuntimeD4rtException(
      "Cannot access property '$memberName' on target of type ${prefixValue?.runtimeType}.",
    );
  }
}