Skip to content

Conversation

mediremi
Copy link
Member

Currently, the following:

@tag("name")
type animal = Cat({name: string})

let cat: animal = Cat({name: "my cat"})

compiles to:

let cat = {
  name: "Cat",
  name: "my cat"
};

export {
  cat,
}

Since we don't treat the overlap in tag name and inline record field as a compiler error, this can lead to issues at runtime:

@tag("name")
type animal = Cat({name: string}) | Dog({age: int})

let cat: animal = Cat({name: "my cat"})

let classifyAnimal = (v: animal) => {
  switch v {
  | Cat(_) => "cat"
  | Dog(_) => "dog"
  }
}

classifyAnimal(cat)->Console.log // "dog"

In this PR, I've fixed this issue by making inline record fields that overlap with a variant's tag a compile error.

I've also added checks for duplicate @as tags on inline record fields.

| _ -> ());
!st

let process_as_name (attrs : Parsetree.attributes) =
Copy link
Member Author

Choose a reason for hiding this comment

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

This function is based on process_tag_name, located above:

let process_tag_name (attrs : Parsetree.attributes) =
let st = ref None in
Ext_list.iter attrs (fun ({txt; loc}, payload) ->
match txt with
| "tag" ->
if !st = None then (
(match Ast_payload.is_single_string payload with
| None -> ()
| Some (s, _dec) -> st := Some s);
if !st = None then raise (Error (loc, InvalidVariantTagAnnotation)))
else raise (Error (loc, Duplicated_bs_as))
| _ -> ());
!st

@mediremi mediremi marked this pull request as ready for review September 11, 2025 09:24
@mediremi mediremi requested review from cristianoc, tsnobip and zth and removed request for zth September 11, 2025 09:24
Copy link
Member

@zth zth left a comment

Choose a reason for hiding this comment

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

Nice! Looks good to me. But good if @cristianoc takes a look as well.

Copy link

pkg-pr-new bot commented Sep 11, 2025

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript-lang/rescript@7875

@rescript/darwin-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-arm64@7875

@rescript/darwin-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-x64@7875

@rescript/linux-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-arm64@7875

@rescript/linux-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-x64@7875

@rescript/runtime

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/runtime@7875

@rescript/win32-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/win32-x64@7875

commit: 08afd62

Copy link
Member

@tsnobip tsnobip left a comment

Choose a reason for hiding this comment

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

nice improvement! Thanks @mediremi!

@mediremi
Copy link
Member Author

@cristianoc would you be able to have a quick check of this PR when you have time please? Just in case I've broken something without realising

Copy link
Collaborator

@cristianoc cristianoc left a comment

Choose a reason for hiding this comment

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

Looks great!
Left a comment on reuse.
@zth any suggestions for the phrasing of the error to make it super clear?

@zth
Copy link
Member

zth commented Sep 17, 2025

In terms of the message, the only thing I don't think is clear now and that could perhaps be tweaked is that the @tag names an actual expected field on the runtime object, which is why you can't have a conflicting inline record field with the same name.

@mediremi
Copy link
Member Author

mediremi commented Sep 26, 2025

I replaced process_as_name with the existing helper process_tag_type in 5c5f2bd

I clarified the error message to mention both the field name in the type and its runtime value in 40d5e14

@mediremi mediremi force-pushed the compiler-error-variant-tag-constructor-field branch from 00076d7 to 40d5e14 Compare September 26, 2025 11:16
@mediremi mediremi enabled auto-merge (squash) September 26, 2025 11:40
@mediremi mediremi merged commit 9f65e63 into rescript-lang:master Sep 26, 2025
25 checks passed
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.

5 participants