createAndInitializeInstance method

InterpretedInstance createAndInitializeInstance(
  1. InterpreterVisitor visitor,
  2. List<RuntimeType>? typeArguments
)

Implementation

InterpretedInstance createAndInitializeInstance(
  InterpreterVisitor visitor,
  List<RuntimeType>? typeArguments,
) {
  // Prevent direct instantiation of abstract classes
  if (isAbstract) {
    throw RuntimeD4rtException("Cannot instantiate abstract class '$name'.");
  }

  // Get validated effective type arguments
  final effectiveTypeArgs = _getValidatedTypeArguments(typeArguments);

  // 1. Create the instance with a link to the class
  final instance = InterpretedInstance(
    this,
    typeArguments: effectiveTypeArgs,
  ); // Pass only the class

  // Use the environment where the class was defined as the outer scope
  // for evaluating initializers. We need to traverse the hierarchy.
  final originalVisitorEnv = visitor.environment;

  // Traverse the class hierarchy from top (Object/superclass) down to this class
  List<InterpretedClass> hierarchy = [];
  InterpretedClass? current = this;
  while (current != null) {
    hierarchy.insert(0, current); // Insert at beginning to get top-down order
    current = current.superclass;
  }

  // Initialize fields for each class in the hierarchy
  for (final klassInHierarchy in hierarchy) {
    // Create a temporary environment for this specific class's initializers,
    // enclosing the environment where *that* class was defined.
    final fieldInitEnv = Environment(
      enclosing: klassInHierarchy.classDefinitionEnvironment,
    );
    fieldInitEnv.define('this', instance); // Define 'this' for initializers

    try {
      visitor.environment =
          fieldInitEnv; // Set visitor env for this class's initializers

      // Initialize fields declared IN THIS CLASS
      for (final fieldDecl in klassInHierarchy.fieldDeclarations) {
        if (!fieldDecl.isStatic) {
          for (final variable in fieldDecl.fields?.variables ?? []) {
            final fieldName = variable.name?.name ?? '';
            final isLate = fieldDecl.fields?.isLate ?? false;
            final isFinal = fieldDecl.fields?.isFinal ?? false;

            if (isLate) {
              // Handle late instance field
              if (variable.initializer != null) {
                // Late instance field with lazy initializer
                final lateVar = LateVariable(fieldName, () {
                  // Create a closure that will evaluate the initializer when accessed
                  final savedEnv = visitor.environment;
                  try {
                    visitor.environment = fieldInitEnv;
                    return variable.initializer!.accept<Object?>(visitor);
                  } finally {
                    visitor.environment = savedEnv;
                  }
                }, isFinal: isFinal);
                instance._fields[fieldName] = lateVar;
                Logger.debug(
                  "[Instance Init] Defined late instance field '$fieldName' with lazy initializer.",
                );
              } else {
                // Late instance field without initializer
                final lateVar = LateVariable(
                  fieldName,
                  null,
                  isFinal: isFinal,
                );
                instance._fields[fieldName] = lateVar;
                Logger.debug(
                  "[Instance Init] Defined late instance field '$fieldName' without initializer.",
                );
              }
            } else {
              // Regular field handling
              if (variable.initializer != null) {
                final value = variable.initializer!.accept<Object?>(visitor);
                // Directly set the field on the instance map
                instance._fields[fieldName] = value;
              } else {
                // Ensure field exists even without initializer (Dart default is null)
                instance._fields.putIfAbsent(fieldName, () => null);
              }
            }
          }
        }
      }

      // Initialize fields from MIXINS applied to this class
      // Iterate in application order (0 to n-1) so later mixins overwrite earlier ones
      for (final mixin in klassInHierarchy.mixins) {
        // Each mixin's field initializers run in the mixin's definition environment
        // with 'this' bound to the instance being created.
        final mixinFieldInitEnv = Environment(
          enclosing: mixin.classDefinitionEnvironment,
        );
        mixinFieldInitEnv.define('this', instance);

        // Temporarily set visitor environment for this mixin's initializers
        final originalEnvBeforeMixin = visitor.environment;
        try {
          visitor.environment = mixinFieldInitEnv;
          for (final fieldDecl in mixin.fieldDeclarations) {
            if (!fieldDecl.isStatic) {
              for (final variable in fieldDecl.fields?.variables ?? []) {
                final fieldName = variable.name?.name ?? '';
                if (variable.initializer != null) {
                  final value = variable.initializer!.accept<Object?>(
                    visitor,
                  );
                  // Set (or overwrite) the field on the instance
                  instance._fields[fieldName] = value;
                  Logger.debug(
                    "[Instance Init] Initialized mixin field '${klassInHierarchy.name}.$fieldName' from mixin '${mixin.name}' with value: $value",
                  );
                } else {
                  // Ensure field exists even if not initialized (Dart default is null)
                  // Only set null if field wasn't already set by class or previous mixin
                  instance._fields.putIfAbsent(fieldName, () {
                    Logger.debug(
                      "[Instance Init] Initialized mixin field '${klassInHierarchy.name}.$fieldName' from mixin '${mixin.name}' to null (default)",
                    );
                    return null;
                  });
                }
              }
            }
          }
        } finally {
          // Restore visitor environment after this mixin's initializers
          visitor.environment = originalEnvBeforeMixin;
        }
      }
    } finally {
      // Restore visitor environment after this class's initializers
      visitor.environment = originalVisitorEnv;
    }
  }

  // Instance fields from class hierarchy AND mixins should now be initialized.
  Logger.debug(
    "[Instance Init] Finished instance initialization for '$name'. Fields: ${instance._fields}",
  );

  return instance;
}