@@ -80,6 +80,7 @@ exception
8080exception MissingLabeledParamType ( {name: string}) ;
8181exception MissingUnlabeledParamType ( {idx: int}) ;
8282exception MissingReturnType ;
83+ exception AttributeAppearsMultipleTimes ( {attr: string}) ;
8384exception
8485 InvalidAttribute ( {
8586 name: string,
@@ -115,6 +116,10 @@ let () =
115116 | MissingReturnType =>
116117 let msg = "Unable to find a return type. Please file an issue!" ;
117118 Some (msg);
119+ | AttributeAppearsMultipleTimes ({attr}) =>
120+ let msg =
121+ Printf . sprintf("Attribute @% s is only allowed to appear once." , attr);
122+ Some (msg);
118123 | InvalidAttribute ({name, attr}) =>
119124 let msg = Printf . sprintf("Invalid attribute @% s on % s " , attr, name);
120125 Some (msg);
@@ -292,16 +297,18 @@ let for_value_description =
292297 examples,
293298 )
294299 | Since ({attr_version}) =>
295- // TODO(#787): Should we fail if more than one `@since` attribute?
296- (
297- deprecations,
298- Some ({since_version: attr_version}),
299- history,
300- params,
301- returns,
302- throws,
303- examples,
304- )
300+ switch (since) {
301+ | Some (_ ) => raise (AttributeAppearsMultipleTimes ({attr: "since" }))
302+ | None => (
303+ deprecations,
304+ Some ({since_version: attr_version}),
305+ history,
306+ params,
307+ returns,
308+ throws,
309+ examples,
310+ )
311+ }
305312 | History ({attr_version: history_version , attr_desc: history_msg }) => (
306313 deprecations,
307314 since,
@@ -347,20 +354,25 @@ let for_value_description =
347354 examples,
348355 );
349356 | Returns ({attr_desc: returns_msg }) =>
350- let returns_type =
351- switch (return_type) {
352- | Some (typ ) => Printtyp . string_of_type_sch(typ)
353- | None => raise (MissingReturnType )
354- };
355- (
356- deprecations,
357- since,
358- history,
359- params,
360- Some ({returns_msg, returns_type}),
361- throws,
362- examples,
363- );
357+ switch (returns) {
358+ | Some (_ ) =>
359+ raise (AttributeAppearsMultipleTimes ({attr: "returns" }))
360+ | None =>
361+ let returns_type =
362+ switch (return_type) {
363+ | Some (typ ) => Printtyp . string_of_type_sch(typ)
364+ | None => raise (MissingReturnType )
365+ };
366+ (
367+ deprecations,
368+ since,
369+ history,
370+ params,
371+ Some ({returns_msg, returns_type}),
372+ throws,
373+ examples,
374+ );
375+ }
364376 | Throws ({attr_type: throw_type , attr_desc: throw_msg }) => (
365377 deprecations,
366378 since,
@@ -427,13 +439,15 @@ let for_type_declaration =
427439 examples,
428440 )
429441 | Since ({attr_version}) =>
430- // TODO(#787): Should we fail if more than one `@since` attribute?
431- (
432- deprecations,
433- Some ({since_version: attr_version}),
434- history,
435- examples,
436- )
442+ switch (since) {
443+ | Some (_ ) => raise (AttributeAppearsMultipleTimes ({attr: "since" }))
444+ | None => (
445+ deprecations,
446+ Some ({since_version: attr_version}),
447+ history,
448+ examples,
449+ )
450+ }
437451 | History ({attr_version: history_version , attr_desc: history_msg }) => (
438452 deprecations,
439453 since,
@@ -554,13 +568,15 @@ and for_signature_items =
554568 examples,
555569 )
556570 | Since ({attr_version}) =>
557- // TODO(#787): Should we fail if more than one `@since` attribute?
558- (
559- deprecations,
560- Some ({since_version: attr_version}),
561- history,
562- examples,
563- )
571+ switch (since) {
572+ | Some (_ ) => raise (AttributeAppearsMultipleTimes ({attr: "since" }))
573+ | None => (
574+ deprecations,
575+ Some ({since_version: attr_version}),
576+ history,
577+ examples,
578+ )
579+ }
564580 | History ({attr_version: history_version , attr_desc: history_msg }) => (
565581 deprecations,
566582 since,
0 commit comments