fix(api): emit bare interface for all sealed-interface unions

Optional fields whose type was a sealed-interface union without an
auto-decode discriminator (BotCommandScope, InputMedia, InputPaidMedia,
InputProfilePhoto, InputStoryContent, InputMessageContent,
InputPollMedia, InputPollOptionMedia, InlineQueryResult,
PassportElementError) were emitted as *<Union> — pointer to interface,
which is a Go anti-pattern: interfaces are already nil-able, and
callers were forced to take addresses of concrete variants.

The codegen path goType() guarded against pointer-wrapping using
knownDiscriminators (only 13 unions with auto-decode dispatch), missing
the 10 marker-only sealed interfaces. New package var
knownInterfaceTypes is built from buildUnionTypeSet at emitter
construction and covers both kinds. goType() now consults that.

Net effect:
- api/methods.gen.go: 3 *BotCommandScope and 2 *InputPollMedia fields
  become bare interface
- api/types.gen.go: 14 *InputMessageContent and 1 *InputPollOptionMedia
  fields become bare interface

Regression tests in api/unionparam_test.go cover both shapes:
direct concrete-variant assignment, and nil omitempty on the bare
interface field.
This commit is contained in:
2026-05-09 19:06:59 +01:00
parent 13ea7097e1
commit 6ab80c27e1
5 changed files with 135 additions and 49 deletions
+19 -19
View File
@@ -1288,7 +1288,7 @@ type InputPollOption struct {
// Optional. A JSON-serialized list of special entities that appear in the poll option text. It can be specified instead of text_parse_mode
TextEntities []MessageEntity `json:"text_entities,omitempty"`
// Optional. Media added to the poll option
Media *InputPollOptionMedia `json:"media,omitempty"`
Media InputPollOptionMedia `json:"media,omitempty"`
}
// This object represents an answer of a user in a non-anonymous poll.
@@ -4550,7 +4550,7 @@ type InlineQueryResultPhoto struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the photo
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to an animated GIF file. By default, this animated GIF file will be sent by the user with optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the animation.
@@ -4584,7 +4584,7 @@ type InlineQueryResultGif struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the GIF animation
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to a video animation (H.264/MPEG-4 AVC video without sound). By default, this animated MPEG-4 file will be sent by the user with optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the animation.
@@ -4618,7 +4618,7 @@ type InlineQueryResultMpeg4Gif struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the video animation
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to a page containing an embedded video player or a video file. By default, this video file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the video.
@@ -4655,7 +4655,7 @@ type InlineQueryResultVideo struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the video. This field is required if InlineQueryResultVideo is used to send an HTML-page as a result (e.g., a YouTube video).
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to an MP3 audio file. By default, this audio file will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the audio.
@@ -4681,7 +4681,7 @@ type InlineQueryResultAudio struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the audio
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to a voice recording in an .OGG container encoded with OPUS. By default, this voice recording will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the the voice message.
@@ -4705,7 +4705,7 @@ type InlineQueryResultVoice struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the voice recording
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to a file. By default, this file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the file. Currently, only .PDF and .ZIP files can be sent using this method.
@@ -4731,7 +4731,7 @@ type InlineQueryResultDocument struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the file
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
// Optional. URL of the thumbnail (JPEG only) for the file
ThumbnailURL string `json:"thumbnail_url,omitempty"`
// Optional. Thumbnail width
@@ -4763,7 +4763,7 @@ type InlineQueryResultLocation struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the location
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
// Optional. Url of the thumbnail for the result
ThumbnailURL string `json:"thumbnail_url,omitempty"`
// Optional. Thumbnail width
@@ -4797,7 +4797,7 @@ type InlineQueryResultVenue struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the venue
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
// Optional. Url of the thumbnail for the result
ThumbnailURL string `json:"thumbnail_url,omitempty"`
// Optional. Thumbnail width
@@ -4823,7 +4823,7 @@ type InlineQueryResultContact struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the contact
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
// Optional. Url of the thumbnail for the result
ThumbnailURL string `json:"thumbnail_url,omitempty"`
// Optional. Thumbnail width
@@ -4867,7 +4867,7 @@ type InlineQueryResultCachedPhoto struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the photo
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to an animated GIF file stored on the Telegram servers. By default, this animated GIF file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with specified content instead of the animation.
@@ -4891,7 +4891,7 @@ type InlineQueryResultCachedGif struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the GIF animation
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to a video animation (H.264/MPEG-4 AVC video without sound) stored on the Telegram servers. By default, this animated MPEG-4 file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the animation.
@@ -4915,7 +4915,7 @@ type InlineQueryResultCachedMpeg4Gif struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the video animation
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to a sticker stored on the Telegram servers. By default, this sticker will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the sticker.
@@ -4929,7 +4929,7 @@ type InlineQueryResultCachedSticker struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the sticker
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to a file stored on the Telegram servers. By default, this file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the file.
@@ -4953,7 +4953,7 @@ type InlineQueryResultCachedDocument struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the file
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to a video file stored on the Telegram servers. By default, this video file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the video.
@@ -4979,7 +4979,7 @@ type InlineQueryResultCachedVideo struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the video
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to a voice message stored on the Telegram servers. By default, this voice message will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the voice message.
@@ -5001,7 +5001,7 @@ type InlineQueryResultCachedVoice struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the voice message
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// Represents a link to an MP3 audio file stored on the Telegram servers. By default, this audio file will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the audio.
@@ -5021,7 +5021,7 @@ type InlineQueryResultCachedAudio struct {
// Optional. Inline keyboard attached to the message
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
// Optional. Content of the message to be sent instead of the audio
InputMessageContent *InputMessageContent `json:"input_message_content,omitempty"`
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
}
// InputMessageContent is a union type. The following concrete variants implement