Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting static setter: Null check operator used on a null value #207

Open
fischerscode opened this issue Jun 16, 2024 · 0 comments
Open

Comments

@fischerscode
Copy link

It seems like setting static setters / fields doesn't work.
The following test fails with Null check operator used on a null value during compiler.compile.

When removing assign(), the dart_eval code compiles. And the static getter works just fine.

Stacktrace
Null check operator used on a null value
package:dart_eval/src/eval/compiler/reference.dart 101:71              IdentifierReference.setValue
package:dart_eval/src/eval/compiler/expression/assignment.dart 19:14   compileAssignmentExpression
package:dart_eval/src/eval/compiler/expression/expression.dart 34:12   compileExpression
package:dart_eval/src/eval/compiler/expression/expression.dart 106:12  compileExpressionAndDiscardResult
package:dart_eval/src/eval/compiler/statement/statement.dart 26:15     compileStatement
package:dart_eval/src/eval/compiler/statement/block.dart 19:20         compileBlock
package:dart_eval/src/eval/compiler/declaration/function.dart 84:14    compileFunctionDeclaration
package:dart_eval/src/eval/compiler/declaration/declaration.dart 24:5  compileDeclaration
package:dart_eval/src/eval/compiler/compiler.dart 492:11               Compiler.compileSources.<fn>.<fn>
dart:collection                                                        _LinkedHashMapMixin.forEach
package:dart_eval/src/eval/compiler/compiler.dart 481:15               Compiler.compileSources.<fn>
dart:collection                                                        _LinkedHashMapMixin.forEach
package:dart_eval/src/eval/compiler/compiler.dart 477:32               Compiler.compileSources
package:dart_eval/src/eval/compiler/compiler.dart 163:12               Compiler.compile
test\eval\bug_test.dart 191:42                                         main.<fn>
Entire test file:
import 'package:dart_eval/dart_eval.dart';
import 'package:test/test.dart';

import 'package:dart_eval/dart_eval_bridge.dart';
import 'package:dart_eval/dart_eval_extensions.dart';
import 'package:dart_eval/stdlib/core.dart';

class TestClass {
  static int value = 0;
}

class $TestClass implements $Instance {
  $TestClass.wrap(this.$value);

  static final $type = BridgeTypeSpec(
    'package:my_package/file.dart',
    'TestClass',
  );

  static final $declaration = BridgeClassDef(
    BridgeClassType(
      $type.ref,
      $extends: BridgeTypeRef(BridgeTypeSpec(
        'dart:core',
        'Object',
      )),
      $implements: [],
      $with: [],
      isAbstract: false,
    ),
    constructors: {
      '': BridgeConstructorDef(
        BridgeFunctionDef(
          returns: $type.ref.annotate,
          params: [],
          namedParams: [],
          generics: {},
        ),
        isFactory: false,
      )
    },
    methods: {},
    getters: {
      'value': BridgeMethodDef(
        BridgeFunctionDef(
          returns: BridgeTypeRef(
            BridgeTypeSpec(
              'dart:core',
              'int',
            ),
            [],
          ).annotate,
          params: [],
          namedParams: [],
          generics: {},
        ),
        isStatic: true,
      ),
    },
    setters: {
      'value': BridgeMethodDef(
        BridgeFunctionDef(
          returns: CoreTypes.voidType.ref.annotate,
          params: [
            '_value'.param(BridgeTypeRef(
              BridgeTypeSpec(
                'dart:core',
                'int',
              ),
              [],
            ).annotate)
          ],
          namedParams: [],
          generics: {},
        ),
        isStatic: true,
      ),
    },
    bridge: false,
    wrap: true,
  );

  @override
  final TestClass $value;

  late final $Instance _$superWrapper = $Object($value);

  static void configureForCompile(BridgeDeclarationRegistry registry) {
    registry.defineBridgeClass($declaration);
  }

  static void configureForRuntime(Runtime runtime) {
    runtime.registerBridgeFunc(
      'package:my_package/file.dart',
      'TestClass.value*g',
      $TestClass.$g$value,
    );
    runtime.registerBridgeFunc(
      'package:my_package/file.dart',
      'TestClass.value*s',
      $TestClass.$s$value,
    );
    runtime.registerBridgeFunc(
      'package:my_package/file.dart',
      'TestClass.',
      $TestClass.$new,
    );
  }

  @override
  get $reified => $value;

  static $Value? $new(
    Runtime runtime,
    $Value? target,
    List<$Value?> args,
  ) {
    return $TestClass.wrap(TestClass());
  }

  @override
  $Value? $getProperty(
    Runtime runtime,
    String identifier,
  ) {
    switch (identifier) {
      case 'value':
        return $int(TestClass.value);
      default:
        return _$superWrapper.$getProperty(
          runtime,
          identifier,
        );
    }
  }

  @override
  void $setProperty(
    Runtime runtime,
    String identifier,
    $Value value,
  ) {
    switch (identifier) {
      case 'value':
        TestClass.value = ($Value $) {
          final $$ = ($ as dynamic);
          return $$ is! int ? ($.$reified as int) : $$;
        }(value);
      default:
        _$superWrapper.$setProperty(
          runtime,
          identifier,
          value,
        );
    }
  }

  @override
  int $getRuntimeType(Runtime runtime) {
    return runtime.lookupType($type);
  }

  static $Value? $g$value(
    Runtime runtime,
    $Value? target,
    List<$Value?> args,
  ) {
    return $int(TestClass.value);
  }

  static $Value? $s$value(
    Runtime runtime,
    $Value? target,
    List<$Value?> args,
  ) {
    TestClass.value = ($Value $) {
      final $$ = ($ as dynamic);
      return $$ is! int ? ($.$reified as int) : $$;
    }(args[0]!);
    return null;
  }
}

void main() {
  late Runtime runtime;

  setUpAll(() {
    var compiler = Compiler();
    $TestClass.configureForCompile(compiler);

    runtime = Runtime.ofProgram(compiler.compile({
      'eval_builder': {
        'main.dart': '''
      import 'package:my_package/file.dart';
      int value() {
        return TestClass.value;
      }
      void assign() {
        TestClass.value = 123;
      }
    '''
      }
    }));
    $TestClass.configureForRuntime(runtime);
  });

  test('value', () {
    TestClass.value = 987;
    expect(
        runtime.executeLib('package:eval_builder/main.dart', 'value', []), 987);
  });
  test('assign', () {
    TestClass.value = 0;
    runtime.executeLib('package:eval_builder/main.dart', 'assign', []);
    expect(TestClass.value, 123);
  }, skip: true);
}
void main() {
  late Runtime runtime;

  setUpAll(() {
    var compiler = Compiler();
    $TestClass.configureForCompile(compiler);

    runtime = Runtime.ofProgram(compiler.compile({
      'eval_builder': {
        'main.dart': '''
      import 'package:my_package/file.dart';
      int value() {
        return TestClass.value;
      }
      void assign() {
        TestClass.value = 123;
      }
    '''
      }
    }));
    $TestClass.configureForRuntime(runtime);
  });

  test('value', () {
    TestClass.value = 987;
    expect(
        runtime.executeLib('package:eval_builder/main.dart', 'value', []), 987);
  });
  test('assign', () {
    TestClass.value = 0;
    runtime.executeLib('package:eval_builder/main.dart', 'assign', []);
    expect(TestClass.value, 123);
  }, skip: true);
}

I've run into this while working on a code builder. But I'm pretty confident that this is not related to me doing something wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant