Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 28, 2026

Problem

Regenerating SDKs from TypeSpec (previously from autorest) drops public constructors, breaking existing code. Example from Azure.Search.Documents:

Previous (autorest):

public abstract partial class SearchIndexerDataIdentity
{
    public SearchIndexerDataIdentity() { }
}

Current (TypeSpec without fix):

public abstract partial class SearchIndexerDataIdentity
{
    private protected SearchIndexerDataIdentity(string odataType) { }
    // Missing public parameterless constructor
}

Changes

Core Implementation

  • TypeProvider.ProcessTypeForBackCompatibility: Extended to process constructors in addition to methods
  • TypeProvider.BuildConstructorsForBackCompatibility: New virtual method for constructor backward compatibility logic
  • ModelProvider.BuildConstructorsForBackCompatibility: Compares current vs LastContractView constructors, generates missing public constructors that delegate to existing ones with default parameters

Signature Matching

  • Custom ConstructorSignatureComparer compares modifiers, parameter count, and parameter types/names

Generated Code

public abstract partial class SearchIndexerDataIdentity
{
    /// <summary> Initializes a new instance of SearchIndexerDataIdentity. </summary>
    public SearchIndexerDataIdentity() : this(odataType: default) { }
    
    private protected SearchIndexerDataIdentity(string odataType) 
    {
        OdataType = odataType;
    }
}

Testing

  • Added BackCompat_MissingPublicParameterlessConstructor test
  • Added BackCompat_MissingPublicConstructorWithParameter test
  • Updated documentation with new "Model Constructors" section
Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug]: Backward Compatibility not generating pre-existing public constructors</issue_title>
<issue_description>### Describe the bug

Pre-existing public constructors should not be missing from the generated code. This should be another Back Compat scenario. See Backward Compatibility Support for more details.

Generating Azure.Search.Documents have the issue where a public constructor is missing, for instance, this is what the previously generated code from autorest looks like:

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// <auto-generated/>

#nullable disable

using System;
using System.Collections.Generic;

namespace Azure.Search.Documents.Indexes.Models
{
    /// <summary>
    /// Abstract base type for data identities.
    /// Please note <see cref="SearchIndexerDataIdentity"/> is the base class. According to the scenario, a derived class of the base class might need to be assigned here, or this property needs to be casted to one of the possible derived classes.
    /// The available derived classes include <see cref="SearchIndexerDataNoneIdentity"/> and <see cref="SearchIndexerDataUserAssignedIdentity"/>.
    /// </summary>
    public abstract partial class SearchIndexerDataIdentity
    {
        /// <summary>
        /// Keeps track of any properties unknown to the library.
        /// <para>
        /// To assign an object to the value of this property use <see cref="BinaryData.FromObjectAsJson{T}(T, System.Text.Json.JsonSerializerOptions?)"/>.
        /// </para>
        /// <para>
        /// To assign an already formatted json string to this property use <see cref="BinaryData.FromString(string)"/>.
        /// </para>
        /// <para>
        /// Examples:
        /// <list type="bullet">
        /// <item>
        /// <term>BinaryData.FromObjectAsJson("foo")</term>
        /// <description>Creates a payload of "foo".</description>
        /// </item>
        /// <item>
        /// <term>BinaryData.FromString("\"foo\"")</term>
        /// <description>Creates a payload of "foo".</description>
        /// </item>
        /// <item>
        /// <term>BinaryData.FromObjectAsJson(new { key = "value" })</term>
        /// <description>Creates a payload of { "key": "value" }.</description>
        /// </item>
        /// <item>
        /// <term>BinaryData.FromString("{\"key\": \"value\"}")</term>
        /// <description>Creates a payload of { "key": "value" }.</description>
        /// </item>
        /// </list>
        /// </para>
        /// </summary>
        private protected IDictionary<string, BinaryData> _serializedAdditionalRawData;

        /// <summary> Initializes a new instance of <see cref="SearchIndexerDataIdentity"/>. </summary>
        public SearchIndexerDataIdentity()
        {
        }

        /// <summary> Initializes a new instance of <see cref="SearchIndexerDataIdentity"/>. </summary>
        /// <param name="oDataType"> A URI fragment specifying the type of identity. </param>
        /// <param name="serializedAdditionalRawData"> Keeps track of any properties unknown to the library. </param>
        internal SearchIndexerDataIdentity(string oDataType, IDictionary<string, BinaryData> serializedAdditionalRawData)
        {
            ODataType = oDataType;
            _serializedAdditionalRawData = serializedAdditionalRawData;
        }

        /// <summary> A URI fragment specifying the type of identity. </summary>
        internal string ODataType { get; set; }
    }
}

and the new generated model looks like:

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// <auto-generated/>

#nullable disable

using System;
using System.Collections.Generic;

namespace Azure.Search.Documents.Models
{
    /// <summary>
    /// Abstract base type for data identities.
    /// Please note this is the abstract base class. The derived classes available for instantiation are: <see cref="SearchIndexerDataNoneIdentity"/> and <see cref="SearchIndexerDataUserAssignedIdentity"/>.
    /// </summary>
    public abstract partial class SearchIndexerDataIdentity
    {
        /// <summary> Keeps track of any properties unknown to the library. </summary>
        private protected readonly IDictionary<string, BinaryData> _additionalBinaryDataProperties;

        /// <summary> Initializes a new instance of <see cref="SearchIndexerDataIdentity"/>. </summary>
        /// <param name="odataType"> A URI fragment specifying the type of identity. </param>
        private protected SearchIndexerDataIdentity(string odataType)
        {
            OdataType = odataType;
        }

        /// <summary> Initializes a new instance of <see cref="SearchIndexerDataIdentity"/>. </summary>
  ...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes microsoft/typespec#9483

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

Copilot AI changed the title [WIP] Fix backward compatibility for public constructors Add backward compatibility support for missing public constructors Jan 28, 2026
Copilot AI requested a review from JonathanCrd January 28, 2026 00:32
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.

2 participants