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

Inconsistent parsing of optional fields in typedefs when using class notation #65

Open
arotter opened this issue Jun 3, 2022 · 0 comments

Comments

@arotter
Copy link

arotter commented Jun 3, 2022

Description

I have a test file with two typedefs, one using object notation and one using class notation. When parsing that file the resulting data is inconsistent in retaining information about optional fields depending on which notation was used. Object notation works fine, class notation is misbehaving.

package test;

typedef TestA = {
	foo:String,
	?bar:Int,
	?baz:Bool
}

typedef TestB = {
	var foo:String;
	var ?bar:Int;
	@:optional var baz:Bool;
}

Current result

TestA gets parsed as (code snippet under fold)
{
  name: 'TestA',
  doc: '',
  meta: [],
  params: [],
  flags: [],
  data: {
    _hx_index: 2,
    fields: [
      {
        name: 'foo',
        meta: [],
        access: [],
        doc: null,
        kind: {
          _hx_index: 0,
          t: {
            _hx_index: 0,
            p: { pack: [], name: 'String', params: [], sub: null },
            __enum__: 'haxe.macro.ComplexType',
            toString: [Function: $estr]
          },
          e: null,
          __enum__: 'haxe.macro.FieldType',
          toString: [Function: $estr]
        },
        pos: { file: '<null>', min: 34, max: 45 }
      },
      {
        name: 'bar',
        meta: [
          {
            name: ':optional',
            params: [],
            pos: { file: '<null>', min: 48, max: 51 }
          }
        ],
        access: [],
        doc: null,
        kind: {
          _hx_index: 0,
          t: {
            _hx_index: 0,
            p: {
              pack: [],
              name: 'Null',
              sub: null,
              params: [
                {
                  _hx_index: 0,
                  t: {
                    _hx_index: 0,
                    p: { pack: [], name: 'Int', params: [], sub: null },
                    __enum__: 'haxe.macro.ComplexType',
                    toString: [Function: $estr]
                  },
                  __enum__: 'haxe.macro.TypeParam',
                  toString: [Function: $estr]
                }
              ]
            },
            __enum__: 'haxe.macro.ComplexType',
            toString: [Function: $estr]
          },
          e: null,
          __enum__: 'haxe.macro.FieldType',
          toString: [Function: $estr]
        },
        pos: { file: '<null>', min: 48, max: 56 }
      },
      {
        name: 'baz',
        meta: [
          {
            name: ':optional',
            params: [],
            pos: { file: '<null>', min: 59, max: 62 }
          }
        ],
        access: [],
        doc: null,
        kind: {
          _hx_index: 0,
          t: {
            _hx_index: 0,
            p: {
              pack: [],
              name: 'Null',
              sub: null,
              params: [
                {
                  _hx_index: 0,
                  t: {
                    _hx_index: 0,
                    p: { pack: [], name: 'Bool', params: [], sub: null },
                    __enum__: 'haxe.macro.ComplexType',
                    toString: [Function: $estr]
                  },
                  __enum__: 'haxe.macro.TypeParam',
                  toString: [Function: $estr]
                }
              ]
            },
            __enum__: 'haxe.macro.ComplexType',
            toString: [Function: $estr]
          },
          e: null,
          __enum__: 'haxe.macro.FieldType',
          toString: [Function: $estr]
        },
        pos: { file: '<null>', min: 59, max: 69 }
      }
    ],
    __enum__: 'haxe.macro.ComplexType',
    toString: [Function: $estr]
  }
}
TestB gets parsed as (code snippet under fold)
{
  name: 'TestB',
  doc: '',
  meta: [],
  params: [],
  flags: [],
  data: {
    _hx_index: 2,
    fields: [
      {
        name: 'foo',
        doc: '',
        meta: [],
        access: [],
        pos: { file: '<null>', min: 90, max: 105 },
        kind: {
          _hx_index: 0,
          t: {
            _hx_index: 0,
            p: { pack: [], name: 'String', params: [], sub: null },
            __enum__: 'haxe.macro.ComplexType',
            toString: [Function: $estr]
          },
          e: null,
          __enum__: 'haxe.macro.FieldType',
          toString: [Function: $estr]
        }
      },
      {
        name: 'bar',
        doc: '',
        meta: [],
        access: [],
        pos: { file: '<null>', min: 107, max: 120 },
        kind: {
          _hx_index: 0,
          t: {
            _hx_index: 0,
            p: { pack: [], name: 'Int', params: [], sub: null },
            __enum__: 'haxe.macro.ComplexType',
            toString: [Function: $estr]
          },
          e: null,
          __enum__: 'haxe.macro.FieldType',
          toString: [Function: $estr]
        }
      },
      {
        name: 'baz',
        doc: '',
        meta: [
          {
            name: ':optional',
            params: [],
            pos: { file: '<null>', min: 123, max: 132 }
          }
        ],
        access: [],
        pos: { file: '<null>', min: 133, max: 146 },
        kind: {
          _hx_index: 0,
          t: {
            _hx_index: 0,
            p: { pack: [], name: 'Bool', params: [], sub: null },
            __enum__: 'haxe.macro.ComplexType',
            toString: [Function: $estr]
          },
          e: null,
          __enum__: 'haxe.macro.FieldType',
          toString: [Function: $estr]
        }
      }
    ],
    __enum__: 'haxe.macro.ComplexType',
    toString: [Function: $estr]
  }
}

The parse data for TestA contains the expected :optional metadata for the optional fields, and their respective types come down to Null<X> which was a bit surprising for me at that moment but is still fine.

However, the parse data for TestB::bar does not contain any information about it being optional (no typing as Null<Int>, no :optional entry in meta), which afaics makes it impossible to know whether that field was optional or not. Additionally, TestB::baz is not the same type as TestA::baz (Bool vs Null<Bool>) despite carrying the :optional metadata.

Using the ? to indicate optional fields should be valid in class notation according to the documentation.

Expected result

Information about fields being optional should be retained regardless of notation used. Also, the data should follow a consistent pattern: if optional fields are typed as Null<X> in one notation then they should also be typed as such when using the other notation.

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