未验证 提交 94c70eb6 编写于 作者: J Julien Couvreur 提交者: GitHub

Record copy ctor must invoke base copy ctor (#45022)

上级 12fbed06
......@@ -3853,6 +3853,7 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression)
{
TypeSymbol constructorReturnType = constructor.ReturnType;
Debug.Assert(constructorReturnType.IsVoidType()); //true of all constructors
NamedTypeSymbol baseType = containingType.BaseTypeNoUseSiteDiagnostics;
// Get the bound arguments and the argument names.
// : this(__arglist()) is legal
......@@ -3949,19 +3950,23 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression)
MemberResolutionResult<MethodSymbol> memberResolutionResult;
ImmutableArray<MethodSymbol> candidateConstructors;
if (TryPerformConstructorOverloadResolution(
initializerType,
analyzedArguments,
WellKnownMemberNames.InstanceConstructorName,
errorLocation,
false, // Don't suppress result diagnostics
diagnostics,
out memberResolutionResult,
out candidateConstructors,
allowProtectedConstructorsOfBaseType: true))
bool found = TryPerformConstructorOverloadResolution(
initializerType,
analyzedArguments,
WellKnownMemberNames.InstanceConstructorName,
errorLocation,
false, // Don't suppress result diagnostics
diagnostics,
out memberResolutionResult,
out candidateConstructors,
allowProtectedConstructorsOfBaseType: true);
MethodSymbol resultMember = memberResolutionResult.Member;
validateRecordCopyConstructor(constructor, baseType, resultMember, errorLocation, diagnostics);
if (found)
{
bool hasErrors = false;
MethodSymbol resultMember = memberResolutionResult.Member;
if (resultMember == constructor)
{
......@@ -3990,7 +3995,6 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression)
var arguments = analyzedArguments.Arguments.ToImmutable();
var refKinds = analyzedArguments.RefKinds.ToImmutableOrNull();
var argsToParamsOpt = memberResolutionResult.Result.ArgsToParamsOpt;
if (!hasErrors)
{
hasErrors = !CheckInvocationArgMixing(
......@@ -4041,6 +4045,36 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression)
{
analyzedArguments.Free();
}
static void validateRecordCopyConstructor(MethodSymbol constructor, NamedTypeSymbol baseType, MethodSymbol resultMember, Location errorLocation, DiagnosticBag diagnostics)
{
if (IsUserDefinedRecordCopyConstructor(constructor))
{
if (baseType.SpecialType == SpecialType.System_Object)
{
if (resultMember is null || resultMember.ContainingType.SpecialType != SpecialType.System_Object)
{
// Record deriving from object must use `base()`, not `this()`
diagnostics.Add(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, errorLocation);
}
return;
}
// Unless the base type is 'object', the constructor should invoke a base type copy constructor
if (resultMember is null || !SynthesizedRecordCopyCtor.HasCopyConstructorSignature(resultMember))
{
diagnostics.Add(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, errorLocation);
}
}
}
}
internal static bool IsUserDefinedRecordCopyConstructor(MethodSymbol constructor)
{
return constructor.ContainingType is SourceNamedTypeSymbol sourceType &&
sourceType.IsRecord &&
SynthesizedRecordCopyCtor.HasCopyConstructorSignature(constructor);
}
private BoundExpression BindImplicitObjectCreationExpression(ImplicitObjectCreationExpressionSyntax node, DiagnosticBag diagnostics)
......
......@@ -3355,8 +3355,10 @@ private BoundNode BindConstructorBody(ConstructorDeclarationSyntax constructor,
Debug.Assert(bodyBinder != null);
if (constructor.Initializer?.IsKind(SyntaxKind.ThisConstructorInitializer) != true &&
ContainingType.GetMembersUnordered().OfType<SynthesizedRecordConstructor>().Any())
ContainingType.GetMembersUnordered().OfType<SynthesizedRecordConstructor>().Any() &&
!SynthesizedRecordCopyCtor.IsCopyConstructor(this.ContainingMember()))
{
// Note: we check the constructor initializer of copy constructors elsewhere
Error(diagnostics, ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, constructor.Initializer?.ThisOrBaseKeyword ?? constructor.Identifier);
}
......
......@@ -6253,4 +6253,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_BadRecordMemberForPositionalParameter" xml:space="preserve">
<value>Record member '{0}' must be a readable instance property of type '{1}' to match positional parameter '{2}'.</value>
</data>
<data name="ERR_NoCopyConstructorInBaseType" xml:space="preserve">
<value>No accessible copy constructor found in base type '{0}'.</value>
</data>
<data name="ERR_CopyConstructorMustInvokeBaseCopyConstructor" xml:space="preserve">
<value>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</value>
</data>
</root>
......@@ -977,7 +977,8 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
// Do not emit initializers if we are invoking another constructor of this class.
includeInitializersInBody = !processedInitializers.BoundInitializers.IsDefaultOrEmpty &&
!HasThisConstructorInitializer(methodSymbol) &&
!(methodSymbol is SynthesizedRecordCopyCtor); // A record copy constructor is special, regular initializers are not supposed to be executed by it.
!(methodSymbol is SynthesizedRecordCopyCtor) &&
!Binder.IsUserDefinedRecordCopyConstructor(methodSymbol); // A record copy constructor is special, regular initializers are not supposed to be executed by it.
body = BindMethodBody(methodSymbol, compilationState, diagsForCurrentMethod, out importChain, out originalBodyNested, out forSemanticModel);
if (diagsForCurrentMethod.HasAnyErrors() && body != null)
......@@ -1846,6 +1847,11 @@ private static void ReportCtorInitializerCycles(MethodSymbol method, BoundExpres
}
}
if (constructor is SynthesizedRecordCopyCtor copyCtor)
{
return GenerateBaseCopyConstructorInitializer(copyCtor, diagnostics);
}
// Now, in order to do overload resolution, we're going to need a binder. There are
// two possible situations:
//
......@@ -1978,6 +1984,53 @@ internal static BoundCall GenerateBaseParameterlessConstructorInitializer(Method
{ WasCompilerGenerated = true };
}
private static BoundCall GenerateBaseCopyConstructorInitializer(SynthesizedRecordCopyCtor constructor, DiagnosticBag diagnostics)
{
NamedTypeSymbol containingType = constructor.ContainingType;
NamedTypeSymbol baseType = containingType.BaseTypeNoUseSiteDiagnostics;
Location diagnosticsLocation = constructor.Locations.FirstOrNone();
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
MethodSymbol baseConstructor = SynthesizedRecordCopyCtor.FindCopyConstructor(baseType, containingType, ref useSiteDiagnostics);
if (baseConstructor is null)
{
diagnostics.Add(ErrorCode.ERR_NoCopyConstructorInBaseType, diagnosticsLocation, baseType);
return null;
}
if (Binder.ReportUseSiteDiagnostics(baseConstructor, diagnostics, diagnosticsLocation))
{
return null;
}
if (!useSiteDiagnostics.IsNullOrEmpty())
{
diagnostics.Add(diagnosticsLocation, useSiteDiagnostics);
}
CSharpSyntaxNode syntax = constructor.GetNonNullSyntaxNode();
BoundExpression receiver = new BoundThisReference(syntax, constructor.ContainingType) { WasCompilerGenerated = true };
BoundExpression argument = new BoundParameter(syntax, constructor.Parameters[0]);
return new BoundCall(
syntax: syntax,
receiverOpt: receiver,
method: baseConstructor,
arguments: ImmutableArray.Create(argument),
argumentNamesOpt: default,
argumentRefKindsOpt: default,
isDelegateCall: false,
expanded: false,
invokedAsExtensionMethod: false,
argsToParamsOpt: default,
resultKind: LookupResultKind.Viable,
binderOpt: null,
type: baseConstructor.ReturnType,
hasErrors: false)
{ WasCompilerGenerated = true };
}
/// <summary>
/// Returns true if the method is a constructor and has a this() constructor initializer.
/// </summary>
......
......@@ -1832,6 +1832,8 @@ internal enum ErrorCode
ERR_BadRecordBase = 8864,
ERR_BadInheritanceFromRecord = 8865,
ERR_BadRecordMemberForPositionalParameter = 8866,
ERR_NoCopyConstructorInBaseType = 8867,
ERR_CopyConstructorMustInvokeBaseCopyConstructor = 8868,
#endregion
......
......@@ -27,7 +27,7 @@ internal sealed class SourceConstructorSymbol : SourceConstructorSymbolBase
ConstructorDeclarationSyntax syntax,
MethodKind methodKind,
DiagnosticBag diagnostics) :
base(containingType, location, syntax, methodKind, diagnostics)
base(containingType, location, syntax)
{
bool hasBlockBody = syntax.Body != null;
_isExpressionBodied = !hasBlockBody && syntax.ExpressionBody != null;
......
......@@ -19,9 +19,7 @@ internal abstract class SourceConstructorSymbolBase : SourceMemberMethodSymbol
protected SourceConstructorSymbolBase(
SourceMemberContainerTypeSymbol containingType,
Location location,
CSharpSyntaxNode syntax,
MethodKind methodKind,
DiagnosticBag diagnostics)
CSharpSyntaxNode syntax)
: base(containingType, syntax.GetReference(), ImmutableArray.Create(location), SyntaxFacts.HasYieldOperations(syntax))
{
Debug.Assert(
......
......@@ -764,6 +764,14 @@ public override bool IsImplicitClass
}
}
internal bool IsRecord
{
get
{
return this.declaration.Declarations[0].Kind == DeclarationKind.Record;
}
}
public override bool IsImplicitlyDeclared
{
get
......
......@@ -18,7 +18,7 @@ internal sealed class SynthesizedRecordConstructor : SourceConstructorSymbolBase
SourceMemberContainerTypeSymbol containingType,
RecordDeclarationSyntax syntax,
DiagnosticBag diagnostics) :
base(containingType, syntax.ParameterList!.GetLocation(), syntax, MethodKind.Constructor, diagnostics)
base(containingType, syntax.ParameterList!.GetLocation(), syntax)
{
this.MakeFlags(MethodKind.Constructor, containingType.IsAbstract ? DeclarationModifiers.Protected : DeclarationModifiers.Public, returnsVoid: true, isExtensionMethod: false);
}
......
......@@ -4,6 +4,8 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.PooledObjects;
......@@ -30,13 +32,15 @@ internal sealed class SynthesizedRecordCopyCtor : SynthesizedInstanceConstructor
public override ImmutableArray<ParameterSymbol> Parameters { get; }
public override Accessibility DeclaredAccessibility => Accessibility.Protected;
internal override LexicalSortKey GetLexicalSortKey() => LexicalSortKey.GetSynthesizedMemberKey(_memberOffset);
internal override void GenerateMethodBodyStatements(SyntheticBoundNodeFactory F, ArrayBuilder<BoundStatement> statements, DiagnosticBag diagnostics)
{
// Tracking issue for copy constructor in inheritance scenario: https://github.com/dotnet/roslyn/issues/44902
// Write assignments to fields
//
// .ctor(DerivedRecordType original) : base((BaseRecordType)original)
// {
// this.field1 = parameter.field1
// ...
......@@ -51,5 +55,42 @@ internal override void GenerateMethodBodyStatements(SyntheticBoundNodeFactory F,
}
}
}
internal static MethodSymbol? FindCopyConstructor(NamedTypeSymbol containingType, NamedTypeSymbol within, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
// We should handle ambiguities once we consider custom modifiers, as we do in overload resolution
// https://github.com/dotnet/roslyn/issues/45077
foreach (var member in containingType.InstanceConstructors)
{
if (HasCopyConstructorSignature(member) &&
!member.HasUnsupportedMetadata &&
AccessCheck.IsSymbolAccessible(member, within, ref useSiteDiagnostics))
{
return member;
}
}
return null;
}
internal static bool IsCopyConstructor(Symbol member)
{
if (member is MethodSymbol { MethodKind: MethodKind.Constructor } method)
{
return HasCopyConstructorSignature(method);
}
return false;
}
internal static bool HasCopyConstructorSignature(MethodSymbol member)
{
NamedTypeSymbol containingType = member.ContainingType;
// We should relax the comparison to AllIgnoreOptions, so that a copy constructor with a custom modifier is recognized
// https://github.com/dotnet/roslyn/issues/45077
return member is MethodSymbol { IsStatic: false, ParameterCount: 1, Arity: 0 } method &&
method.Parameters[0].Type.Equals(containingType, TypeCompareKind.CLRSignatureCompareOptions) &&
method.Parameters[0].RefKind == RefKind.None;
}
}
}
......@@ -197,6 +197,11 @@
<target state="translated">Výraz typu {0} nelze zpracovat vzorem typu {1}. Použijte prosím verzi jazyka {2} nebo vyšší, aby odpovídala otevřenému typu se vzorem konstanty.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">Název {0} neodpovídá příslušnému parametru Deconstruct {1}.</target>
......@@ -492,6 +497,11 @@
<target state="translated">{0}: Typ použitý v příkazu using musí být implicitně převoditelný na System.IDisposable. Neměli jste v úmyslu použít await using místo using?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">Ein Ausdruck vom Typ "{0}" kann nicht von einem Muster vom Typ "{1}" behandelt werden. Verwenden Sie Sprachversion {2} oder höher, um einen offenen Typ mit einem konstanten Muster abzugleichen.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">Der Name "{0}" stimmt nicht mit dem entsprechenden Deconstruct-Parameter "{1}" überein.</target>
......@@ -492,6 +497,11 @@
<target state="translated">"{0}": Der in einer using-Anweisung verwendete Typ muss implizit in "System.IDisposable" konvertierbar sein. Meinten Sie "await using" anstelle von "using"?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">Un patrón de tipo "{0}" no se puede controlar por un patrón de tipo "{1}". Use la versión de lenguaje "{2}" o superior para buscar un tipo abierto con un patrón constante.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">El nombre "{0}" no coincide con el parámetro de "Deconstruct" correspondiente, "{1}".</target>
......@@ -492,6 +497,11 @@
<target state="translated">"{0}": el tipo usado en una instrucción using debe poder convertirse implícitamente en "System.IDisposable". ¿Quiso decir "await using" en lugar de "using"?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">Une expression de type '{0}' ne peut pas être prise en charge par un modèle de type '{1}'. Utilisez la version de langage '{2}' ou une version ultérieure pour faire correspondre un type ouvert à un modèle de constante.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">Le nom '{0}' ne correspond pas au paramètre 'Deconstruct' correspondant '{1}'.</target>
......@@ -492,6 +497,11 @@
<target state="translated">'{0}' : le type utilisé dans une instruction using doit être implicitement convertible en 'System.IDisposable'. Est-ce qu'il ne s'agit pas plutôt de 'await using' au lieu de 'using' ?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">Un'espressione di tipo '{0}' non può essere gestita da un criterio di tipo '{1}'. Usare la versione '{2}' o versioni successive del linguaggio per abbinare un tipo aperto a un criterio costante.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">Il nome '{0}' non corrisponde al parametro '{1}' di 'Deconstruct' corrispondente.</target>
......@@ -492,6 +497,11 @@
<target state="translated">'{0}': il tipo usato in un'istruzione using deve essere convertibile in modo implicito in 'System.IDisposable'. Si intendeva 'await using' invece di 'using'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">型 '{0}' の式を型 '{1}' のパターンで処理することはできません。オープン型と定数パターンを一致させるには、言語バージョン '{2}' 以上をご使用ください。</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">名前 '{0}' は対応する 'Deconstruct' パラメーター '{1}' と一致しません。</target>
......@@ -492,6 +497,11 @@
<target state="translated">'{0}': using ステートメントで使用される型は、暗黙的に 'System.IDisposable' への変換が可能でなければなりません。'using' ではなく 'await using' ですか?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">'{0}' 형식의 식은 '{1}' 형식의 패턴으로 처리할 수 없습니다. 언어 버전 '{2}' 이상을 사용하여 개방형 형식과 상수 패턴을 일치시키세요.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">'{0}' 이름이 해당 'Deconstruct' 매개 변수 '{1}'과(와) 일치하지 않습니다.</target>
......@@ -492,6 +497,11 @@
<target state="translated">'{0}': using 문에 사용된 형식은 암시적으로 'System.IDisposable'로 변환할 수 있어야 합니다. 'using' 대신 'await using'을 사용하시겠습니까?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">Wyrażenie typu „{0}” nie może być obsługiwane przez wzorzec typu „{1}”. Użyj wersji języka „{2}” lub nowszej, aby dopasować typ otwarty za pomocą wzorca stałej.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">Nazwa „{0}” nie jest zgodna z odpowiednim parametrem „Deconstruct” „{1}”.</target>
......@@ -492,6 +497,11 @@
<target state="translated">„{0}”: typ użyty w instrukcji using musi umożliwiać niejawną konwersję na interfejs „System.IDisposable”. Czy chodziło Ci o instrukcję „await using”, a nie „using”?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">Uma expressão do tipo '{0}' não pode ser manipulada por um padrão do tipo '{1}'. Use a versão de linguagem '{2}' ou superior para corresponder a um tipo aberto com um padrão constante.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">O nome '{0}' não corresponde ao parâmetro 'Deconstruct' '{1}'.</target>
......@@ -492,6 +497,11 @@
<target state="translated">'{0}': o tipo usado em uma instrução using deve ser implicitamente conversível em 'System.IDisposable'. Você quis dizer 'await using' em vez de 'using'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">Выражение типа "{0}" не может быть обработано шаблоном типа "{1}". Используйте версию языка "{2}" или более позднюю, чтобы сопоставить открытый тип с постоянным шаблоном.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">Имя "{0}" не соответствует указанному параметру "Deconstruct" "{1}".</target>
......@@ -492,6 +497,11 @@
<target state="translated">"{0}": тип, использованный в операторе using, должен иметь возможность неявного преобразования в System.IDisposable. Вы хотели использовать "await using" вместо "using"?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">'{0}' türünde bir ifade, '{1}' türünde bir desen tarafından işlenemez. Lütfen açık bir türü sabit bir desenle eşleştirmek için '{2}' veya daha yüksek bir dil sürümü kullanın.</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">'{0}' adı ilgili '{1}' 'Deconstruct' parametresiyle eşleşmiyor.</target>
......@@ -492,6 +497,11 @@
<target state="translated">'{0}': using deyiminde kullanılan tür örtük olarak 'System.IDisposable' arabirimine dönüştürülebilir olmalıdır. 'using' yerine 'await using' mi kullanmak istediniz?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">"{0}" 类型的表达式不能由 "{1}" 类型的模式进行处理。请使用语言版本 "{2}" 或更高版本,将开放类型与常数模式进行匹配。</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">名称“{0}”与相应 "Deconstruct" 参数“{1}”不匹配。</target>
......@@ -492,6 +497,11 @@
<target state="translated">“{0}”: using 语句中使用的类型必须可隐式转换为 "System.IDisposable"。是否希望使用 "await using" 而非 "using"?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -197,6 +197,11 @@
<target state="translated">類型 '{0}' 的運算式無法由類型 '{1}' 的模式處理。請使用語言 '{2}' 版或更新版本,以比對開放式類型與常數模式。</target>
<note />
</trans-unit>
<trans-unit id="ERR_CopyConstructorMustInvokeBaseCopyConstructor">
<source>A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</source>
<target state="new">A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMismatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="translated">名稱 '{0}' 與對應的 'Deconstruct' 參數 '{1}' 不相符。</target>
......@@ -492,6 +497,11 @@
<target state="translated">'{0}': using 陳述式中使用的類型必須可以隱含轉換為 'System.IDisposable'。您指的是 'await using' 而不是 'using' 嗎?</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoCopyConstructorInBaseType">
<source>No accessible copy constructor found in base type '{0}'.</source>
<target state="new">No accessible copy constructor found in base type '{0}'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_NoOutputDirectory">
<source>Output directory could not be determined</source>
<target state="new">Output directory could not be determined</target>
......
......@@ -694,7 +694,11 @@ public void RecordClone2_0()
var comp = CreateCompilation(@"
record C(int x, int y)
{
public C(C other) : this(other.x, other.y) { }
public C(C other)
{
x = other.x;
y = other.y;
}
}");
comp.VerifyDiagnostics();
......@@ -720,19 +724,38 @@ .maxstack 1
");
verifier.VerifyIL("C..ctor(C)", @"
{
// Code size 19 (0x13)
.maxstack 3
// Code size 31 (0x1f)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: callvirt ""int C.x.get""
IL_0001: call ""object..ctor()""
IL_0006: ldarg.0
IL_0007: ldarg.1
IL_0008: callvirt ""int C.y.get""
IL_000d: call ""C..ctor(int, int)""
IL_0012: ret
IL_0008: callvirt ""int C.x.get""
IL_000d: call ""void C.x.init""
IL_0012: ldarg.0
IL_0013: ldarg.1
IL_0014: callvirt ""int C.y.get""
IL_0019: call ""void C.y.init""
IL_001e: ret
}
");
}
[Fact]
public void RecordClone2_0_WithThisInitializer()
{
var comp = CreateCompilation(@"
record C(int x, int y)
{
public C(C other) : this(other.x, other.y) { }
}");
comp.VerifyDiagnostics(
// (4,25): error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object.
// public C(C other) : this(other.x, other.y) { }
Diagnostic(ErrorCode.ERR_CopyConstructorMustInvokeBaseCopyConstructor, "this").WithLocation(4, 25)
);
}
[Fact]
[WorkItem(44781, "https://github.com/dotnet/roslyn/issues/44781")]
public void RecordClone2_1()
......@@ -742,11 +765,7 @@ record C(int x, int y)
{
public C(C other) { }
}");
comp.VerifyDiagnostics(
// (4,12): error CS8862: A constructor declared in a record with parameters must have 'this' constructor initializer.
// public C(C other) { }
Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "C").WithLocation(4, 12)
);
comp.VerifyDiagnostics();
}
[Fact]
......@@ -758,11 +777,7 @@ record C(int x, int y)
{
public C(C other) : base() { }
}");
comp.VerifyDiagnostics(
// (4,25): error CS8862: A constructor declared in a record with parameters must have 'this' constructor initializer.
// public C(C other) : base() { }
Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "base").WithLocation(4, 25)
);
comp.VerifyDiagnostics();
}
[Fact]
......@@ -1196,6 +1211,9 @@ enum G : C { }";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics(
// (3,8): error CS8867: No accessible copy constructor found in base type 'A'.
// record B : A { }
Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "B").WithArguments("A").WithLocation(3, 8),
// (3,12): error CS8864: Records may only inherit from object or another record
// record B : A { }
Diagnostic(ErrorCode.ERR_BadRecordBase, "A").WithLocation(3, 12),
......@@ -1209,7 +1227,7 @@ enum G : C { }";
// struct F : C { }
Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "C").WithArguments("C").WithLocation(7, 12),
// (8,10): error CS1008: Type byte, sbyte, short, ushort, int, uint, long, or ulong expected
// enum G : C
// enum G : C { }
Diagnostic(ErrorCode.ERR_IntegralTypeExpected, "C").WithLocation(8, 10)
);
}
......@@ -1240,17 +1258,20 @@ enum H : C { }
});
comp2.VerifyDiagnostics(
// (3,8): error CS8867: No accessible copy constructor found in base type 'A'.
// record E : A { }
Diagnostic(ErrorCode.ERR_NoCopyConstructorInBaseType, "E").WithArguments("A").WithLocation(3, 8),
// (3,12): error CS8864: Records may only inherit from object or another record
// record E : A { }
Diagnostic(ErrorCode.ERR_BadRecordBase, "A").WithLocation(3, 12),
// (4,15): error CS0527: Type 'C' in interface list is not an interface
// interface E : C { }
// interface F : C { }
Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "C").WithArguments("C").WithLocation(4, 15),
// (5,12): error CS0527: Type 'C' in interface list is not an interface
// struct F : C { }
// struct G : C { }
Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "C").WithArguments("C").WithLocation(5, 12),
// (6,10): error CS1008: Type byte, sbyte, short, ushort, int, uint, long, or ulong expected
// enum G : C
// enum H : C { }
Diagnostic(ErrorCode.ERR_IntegralTypeExpected, "C").WithLocation(6, 10)
);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册