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

dynamic field throws 'Null check operator used on a null value' #74

Closed
techouse opened this issue Dec 28, 2022 · 6 comments · Fixed by #78
Closed

dynamic field throws 'Null check operator used on a null value' #74

techouse opened this issue Dec 28, 2022 · 6 comments · Fixed by #78
Labels
bug Something isn't working

Comments

@techouse
Copy link

techouse commented Dec 28, 2022

Describe the issue

I have a dynamic field and the generated code throws a Null check operator used on a null value exception.

Possibly a result of #69 (comment)

Environment details

Dart 2.18.6

To Reproduce

Steps to reproduce the behaviour:

Declare a dynamic field in a class, i.e.

final dynamic action;

and the generated code is

action: action == const $CopyWithPlaceholder() || action == null
        // ignore: unnecessary_non_null_assertion
        ? _value.action!
        // ignore: cast_nullable_to_non_nullable
        : action as dynamic,

This will throw an exception when running unit tests

Null check operator used on a null value
package:alfred_workflow/src/models/alfred_item.g.dart 211:26         _$AlfredItemCWProxyImpl.call
test/fixtures/models/alfred_item_fixture.dart 93:33                  AlfredItemFactory.uid.<fn>
package:data_fixture_dart/factories/fixture_factory.dart 31:30       FixtureFactory.redefine.<fn>
package:data_fixture_dart/definitions/fixture_definition.dart 24:26  FixtureDefinition.makeMany.<fn>
dart:core                                                            new List.generate
package:data_fixture_dart/definitions/fixture_definition.dart 22:12  FixtureDefinition.makeMany
test/unit/models/alfred_items_test.dart 15:10                        main.<fn>

The exception above refers to the line

? _value.action!

where a null check operator (!) is used on dynamic

Expected behaviour

No exception and nullability properly handled on a dynamic field.

Additional context

The only workaround I have found is to use Object? instead of dynamic, like so:

final Object? action;

and the generated code becomes

action: action == const $CopyWithPlaceholder()
        ? _value.action
        // ignore: cast_nullable_to_non_nullable
        : action as Object?,

You can see the workaround in action here

@techouse techouse changed the title dynamic value throws 'Null check operator used on a null value' dynamic field throws 'Null check operator used on a null value' Dec 28, 2022
@numen31337
Copy link
Owner

Hi @techouse,
I attempted to recreate the issue you reported, but I was unable to reproduce the crash you experienced. It's possible that the problem was fixed with the latest version of Dart or that I made a mistake during my testing. Can you take a look at the following test and let me know if it addresses the issue you described?

@techouse
Copy link
Author

It does not crash, it just throws all these error messages.

@numen31337
Copy link
Owner

@techouse Looks like I'm having difficulty replicating the issue and I am wondering if you can guide me on how to see the relevant error messages.

@techouse
Copy link
Author

techouse commented Feb 26, 2023

@numen31337 of course :) The warning only appears when you actually run the code. In the tests it's muted.

I have created a repo demonstrating it here https://github.com/techouse/copy_with_extension_nullability_issue_demo

Way to reproduce it:

  1. clone the repo
  2. install the dependencies
  3. execute
dart run bin/main.dart

This will print

lib/foo.g.dart:53:20: Warning: Operand of null-aware operation '!' has type 'String' which excludes null.
          ? _value.name!
                   ^
Foo(name: bar, value: baz)

@numen31337
Copy link
Owner

For the record, the problem mentioned here is not reflected in #74 (comment). The #74 (comment) is representative of the issue #75 which is a different one. This ticket pertains specifically to instances where an object has a dynamic field that was initialised as null, and subsequently using copyWith on such an object will crash and result in the error message Null check operator used on a null value mentioned earlier.

Test case:

import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:test/test.dart' show test, expect;

part 'gen_nullability_test.g.dart';

@CopyWith()
class TestNullability {
  TestNullability(
    int this.nullableWithNonNullableConstructor,
    this.dynamicField,
    this.integers,
  );

  final int? nullableWithNonNullableConstructor;
  final dynamic dynamicField;
  final List<int> integers;
}

void main() {
  test('TestNullability', () {
    expect(TestNullability(1, null, [1]).copyWith.integers([2]).dynamicField, null);
  });
}

Leads to the crash here:

      dynamicField == const $CopyWithPlaceholder() || dynamicField == null
          // ignore: unnecessary_non_null_assertion
          ? _value.dynamicField! // <--- CRASH
          // ignore: cast_nullable_to_non_nullable
          : dynamicField as dynamic,

@numen31337 numen31337 added the bug Something isn't working label Feb 26, 2023
@techouse
Copy link
Author

techouse commented Feb 26, 2023

@numen31337 correct. My memory on this issue is not the freshest anymore.

I have added more tests into another branch in the same repo https://github.com/techouse/copy_with_extension_nullability_issue_demo/tree/issue-74

Running dart test will produce

$ dart test         
00:00 +1 -1: test/foo_test.dart: issue-74-no-dynamic-value copyWith [E]                                                                                                                                                                
  Null check operator used on a null value
  package:nullability_issue/foo.g.dart 58:25  _$FooCWProxyImpl.call
  test/foo_test.dart 28:28                    main.<fn>.<fn>
  

To run this test again: /usr/local/Caskroom/flutter/3.7.5/flutter/bin/cache/dart-sdk/bin/dart test test/foo_test.dart -p vm --plain-name 'issue-74-no-dynamic-value copyWith'
00:00 +3 -2: test/foo_test.dart: issue-74-null-dynamic-value copyWith [E]                                                                                                                                                              
  Null check operator used on a null value
  package:nullability_issue/foo.g.dart 58:25  _$FooCWProxyImpl.call
  test/foo_test.dart 59:28                    main.<fn>.<fn>
  

To run this test again: /usr/local/Caskroom/flutter/3.7.5/flutter/bin/cache/dart-sdk/bin/dart test test/foo_test.dart -p vm --plain-name 'issue-74-null-dynamic-value copyWith'
00:00 +5 -3: test/foo_test.dart: issue-74-random-null-value copyWith [E]                                                                                                                                                               
  Null check operator used on a null value
  package:nullability_issue/foo.g.dart 58:25  _$FooCWProxyImpl.call
  test/foo_test.dart 88:28                    main.<fn>.<fn>
  

To run this test again: /usr/local/Caskroom/flutter/3.7.5tter/bin/cache/dart-sdk/bin/dart test test/foo_test.dart -p vm --plain-name 'issue-74-random-null-value copyWith'
00:00 +5 -3: Some tests failed.                                                                                                                                                                                                        

Consider enabling the flag chain-stack-traces to receive more detailed exceptions.
For example, 'dart test --chain-stack-traces'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants