@@ -5050,8 +5050,50 @@ and parse_type_representation ?current_type_name_path ?inline_types_context p =
50505050 in
50515051 let kind =
50525052 match p.Parser. token with
5053- | Bar | Uident _ | DocComment _ | At ->
5053+ | Bar | Uident _ | DocComment _ ->
50545054 Parsetree. Ptype_variant (parse_type_constructor_declarations p)
5055+ | At ->
5056+ (* Attributes can prefix either a variant (constructor list), a record, or an
5057+ open/extensible variant marker (`..`). Peek past attributes and any doc
5058+ comments to decide which kind it is. *)
5059+ let after_attrs =
5060+ Parser. lookahead p (fun state ->
5061+ ignore (parse_attributes state);
5062+ let rec skip_docs () =
5063+ match state.Parser. token with
5064+ | DocComment _ -> Parser. next state; skip_docs ()
5065+ | _ -> ()
5066+ in
5067+ skip_docs () ;
5068+ state.Parser. token)
5069+ in
5070+ (match after_attrs with
5071+ | Lbrace ->
5072+ (* consume the attributes and any doc comments before the record *)
5073+ ignore (parse_attributes p);
5074+ let rec skip_docs () =
5075+ match p.Parser. token with
5076+ | DocComment _ -> Parser. next p; skip_docs ()
5077+ | _ -> ()
5078+ in
5079+ skip_docs () ;
5080+ Parsetree. Ptype_record
5081+ (parse_record_declaration ?current_type_name_path ?inline_types_context p)
5082+ | DotDot ->
5083+ (* attributes before an open variant marker; consume attrs/docs then handle `..` *)
5084+ ignore (parse_attributes p);
5085+ let rec skip_docs () =
5086+ match p.Parser. token with
5087+ | DocComment _ -> Parser. next p; skip_docs ()
5088+ | _ -> ()
5089+ in
5090+ skip_docs () ;
5091+ Parser. next p; (* consume DotDot *)
5092+ Ptype_open
5093+ | _ ->
5094+ (* fall back to variant constructor declarations; leave attributes for the
5095+ constructor parsing so they attach to the first constructor. *)
5096+ Parsetree. Ptype_variant (parse_type_constructor_declarations p))
50555097 | Lbrace ->
50565098 Parsetree. Ptype_record
50575099 (parse_record_declaration ?current_type_name_path ?inline_types_context
@@ -5612,22 +5654,42 @@ and parse_type_equation_and_representation ?current_type_name_path
56125654 let priv, kind = parse_type_representation p in
56135655 (None , priv, kind)
56145656 | At -> (
5615- (* Attribute can start a variant constructor or a type manifest.
5616- Look ahead past attributes; if a constructor -like token follows (Uident not immediately
5617- followed by a Dot, or DotDotDot/Bar/DocComment), treat as variant; otherwise manifest *)
5618- let is_variant_after_attrs =
5657+ (* Attributes can start a representation ( variant/record/open variant) or a manifest.
5658+ Look ahead past attributes (and doc comments). If a representation -like token follows,
5659+ parse it as a representation; otherwise treat as a manifest. *)
5660+ let is_representation_after_attrs =
56195661 Parser. lookahead p (fun state ->
56205662 ignore (parse_attributes state);
5663+ (* optionally skip a run of doc comments before deciding *)
5664+ let rec skip_docs () =
5665+ match state.Parser. token with
5666+ | DocComment _ -> Parser. next state; skip_docs ()
5667+ | _ -> ()
5668+ in
5669+ skip_docs () ;
56215670 match state.Parser. token with
5622- | Uident _ -> (
5671+ | Lbrace ->
5672+ (* Disambiguate record declaration vs object type.
5673+ Peek inside the braces; if it looks like an object (String/Dot/DotDot/DotDotDot),
5674+ then this is a manifest type expression, not a representation. If it looks like
5675+ a record field (e.g. Lident or attributes before one), treat as representation. *)
5676+ Parser. next state; (* consume Lbrace *)
5677+ ignore (parse_attributes state);
5678+ skip_docs () ;
5679+ (match state.Parser. token with
5680+ | String _ | Dot | DotDot | DotDotDot -> false (* object type => manifest *)
5681+ | _ -> true ) (* record decl => representation *)
5682+ | Bar -> true (* variant constructor list *)
5683+ | DotDot -> true (* extensible/open variant ".." *)
5684+ | Uident _ -> (* constructor vs module-qualified manifest *)
56235685 Parser. next state;
5624- match state.Parser. token with
5625- | Dot -> false
5626- | _ -> true )
5627- | DotDotDot | Bar | DocComment _ -> true
5686+ ( match state.Parser. token with
5687+ | Dot -> false (* M.t => manifest *)
5688+ | _ -> true ) (* Uident starting a constructor * )
5689+ | DocComment _ -> true (* doc before constructor list *)
56285690 | _ -> false )
56295691 in
5630- if is_variant_after_attrs then
5692+ if is_representation_after_attrs then
56315693 let priv, kind = parse_type_representation p in
56325694 (None , priv, kind)
56335695 else
0 commit comments