Skip to content

Fix issue where build error of newtype escaping its scope #6000

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

Closed
wants to merge 3 commits into from

Conversation

mununki
Copy link
Member

@mununki mununki commented Feb 11, 2023

This PR fixes #5978
JSX4 generates the type declaration of props outside of make function. Any newtype expression of make function could cause the build error of escaping its scope. To fix this issue, this PR generates additional type declarations for newtypes of make function.

@@ -57,7 +57,10 @@ module Select = {
type key
type t
}
type props<'model, 'selected, 'onChange, 'items> = {
type key
and a
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This declares a new type a in the current scope. Will error if a type called a is already in scope. Eg defined just above.
The (type a) should be confined to the body of make.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think so too. I want to avoid to add type declaration. But I don't have a clear idea to fix this:

module type T = {
  type t
}

module V4A2 = {
  type props<'foo> = {foo: 'foo}

  let make = (type a, {foo, _}: props<'foo>) => {
    module T = unpack(foo: T with type t = a)
    foo
  }
  let make = {
    let \"Newtype$V4A2" = (props: props<_>) => make(props)

    \"Newtype$V4A2"
  }
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it compiles OK, should be good.
Might be worth testing a couple of examples by hand and see that it compiles OK, before changing the ppx.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That : props<'foo> should be : props<_> I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That : props<'foo> should be : props<_> I think.

Yes, It works. But How can JSX4 know that foo is going be unpack in the body expression?

// original code
module V4A2 = {
  @react.component
  let make = (type a, ~foo) => {
    module T = unpack(foo: T with type t = a)
    foo
  }
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current ppx passes the core_type of argument to props type. Do you mean passing no parameter to props type?

@react.component
let make = (~a: int) => React.int(a)

// (current) transformed to
type props<'a> = {a: 'a}
let make = ({a, _}: props<int>) => React.int(a)
                         ^^^^^

// (new?)
type props<'a> = {a: 'a}
let make = ({a, _}: props<_>) => React.int(a)
                         ^^^^^

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah no that should stay the same.
I think above you want let make = (type a, ... : props<a>

@@ -67,10 +70,10 @@ module Select = {
@react.component
let make = (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this should be let make = (type a, ...

cristianoc added a commit that referenced this pull request Mar 3, 2023
Make the following changes:
1) Don't replace type variable `a` with `"type-a`",  but leave it alone.
2) If the original `make` uses `(type a b, ...` wrap the first generated `make` with the same new type definitions
3) In the constraint `:props<'a, 'b>` where `'a` and `'b` were not constrained, use `:props<_, _>` instead. This avoids issues when e.g. `'a` is inferred to be a newtype bound in the make function, which would need to be mentioned explicitly and would give a type error.

Fixes #5978
Replaces #6000
@cristianoc
Copy link
Collaborator

This is now replaced by #6029 which adopts some of the suggestions from the discussion.

cristianoc added a commit that referenced this pull request Mar 3, 2023
Make the following changes:
1) Don't replace type variable `a` with `"type-a`",  but leave it alone.
2) If the original `make` uses `(type a b, ...` wrap the first generated `make` with the same new type definitions
3) In the constraint `:props<'a, 'b>` where `'a` and `'b` were not constrained, use `:props<_, _>` instead. This avoids issues when e.g. `'a` is inferred to be a newtype bound in the make function, which would need to be mentioned explicitly and would give a type error.

Fixes #5978
Replaces #6000
cristianoc added a commit that referenced this pull request Mar 3, 2023
Make the following changes:
1) Don't replace type variable `a` with `"type-a`",  but leave it alone.
2) If the original `make` uses `(type a b, ...` wrap the first generated `make` with the same new type definitions
3) In the constraint `:props<'a, 'b>` where `'a` and `'b` were not constrained, use `:props<_, _>` instead. This avoids issues when e.g. `'a` is inferred to be a newtype bound in the make function, which would need to be mentioned explicitly and would give a type error.

Fixes #5978
Replaces #6000
@cristianoc cristianoc closed this Mar 3, 2023
@cristianoc cristianoc deleted the fix-newtype-component-v4 branch March 3, 2023 15:10
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

Successfully merging this pull request may close these issues.

JSXv4: Locally abstract types do not seem to be in scope in the component body
2 participants