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;
}