提交 a4b79958 编写于 作者: A Andy Gocke

Merge remote-tracking branch 'upstream/features/records' into merge-to-records

......@@ -694,7 +694,7 @@ private Binder VisitTypeDeclarationCore(TypeDeclarationSyntax parent)
return VisitTypeDeclarationCore(parent, extraInfo);
}
private Binder VisitTypeDeclarationCore(TypeDeclarationSyntax parent, NodeUsage extraInfo)
internal Binder VisitTypeDeclarationCore(TypeDeclarationSyntax parent, NodeUsage extraInfo)
{
var key = CreateBinderCacheKey(parent, extraInfo);
......@@ -936,7 +936,7 @@ internal Binder VisitCompilationUnit(CompilationUnitSyntax compilationUnit, bool
return result;
}
private static BinderCacheKey CreateBinderCacheKey(CSharpSyntaxNode node, NodeUsage usage)
internal static BinderCacheKey CreateBinderCacheKey(CSharpSyntaxNode node, NodeUsage usage)
{
Debug.Assert(BitArithmeticUtilities.CountBits((uint)usage) <= 1, "Not a flags enum.");
return new BinderCacheKey(node, usage);
......
......@@ -16,8 +16,8 @@ internal enum NodeUsage : byte
AccessorBody = 1 << 0,
OperatorBody = 1 << 0,
NamedTypeBodyOrTypeParameters = 1 << 0,
NamedTypeBaseListOrParameterList = 1 << 1,
NamedTypeBodyOrTypeParameters = 1 << 1, // Cannot share the value with ConstructorBodyOrInitializer
NamedTypeBaseListOrParameterList = 1 << 2, // Cannot share the value with ConstructorBodyOrInitializer
NamespaceBody = 1 << 0,
NamespaceUsings = 1 << 1,
......
......@@ -4,6 +4,7 @@
using System;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
......@@ -129,6 +130,35 @@ internal Binder GetBinder(SyntaxNode node, int position, CSharpSyntaxNode member
return result;
}
internal InMethodBinder GetRecordConstructorInMethodBinder(SynthesizedRecordConstructor constructor)
{
TypeDeclarationSyntax typeDecl = constructor.GetSyntax();
var extraInfo = NodeUsage.ConstructorBodyOrInitializer;
var key = BinderFactoryVisitor.CreateBinderCacheKey(typeDecl, extraInfo);
if (!_binderCache.TryGetValue(key, out Binder resultBinder))
{
// Ctors cannot be generic
Debug.Assert(constructor.Arity == 0, "Generic Ctor, What to do?");
resultBinder = new InMethodBinder(constructor, GetInRecordBodyBinder(typeDecl));
_binderCache.TryAdd(key, resultBinder);
}
return (InMethodBinder)resultBinder;
}
internal Binder GetInRecordBodyBinder(TypeDeclarationSyntax typeDecl)
{
BinderFactoryVisitor visitor = _binderFactoryVisitorPool.Allocate();
visitor.Initialize(position: typeDecl.SpanStart, memberDeclarationOpt: null, memberOpt: null);
Binder resultBinder = visitor.VisitTypeDeclarationCore(typeDecl, NodeUsage.NamedTypeBodyOrTypeParameters);
_binderFactoryVisitorPool.Free(visitor);
return resultBinder;
}
/// <summary>
/// Returns binder that binds usings and aliases
/// </summary>
......
......@@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -95,26 +96,50 @@ internal struct ProcessedFieldInitializers
{
//Can't assert that this is a regular C# compilation, because we could be in a nested type of a script class.
SyntaxReference syntaxRef = initializer.Syntax;
var initializerNode = (EqualsValueClauseSyntax)syntaxRef.GetSyntax();
if (binderFactory == null)
switch (syntaxRef.GetSyntax())
{
binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree);
case EqualsValueClauseSyntax initializerNode:
if (binderFactory == null)
{
binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree);
}
Binder parentBinder = binderFactory.GetBinder(initializerNode);
Debug.Assert((parentBinder.ContainingMemberOrLambda is TypeSymbol containing && TypeSymbol.Equals(containing, fieldSymbol.ContainingType, TypeCompareKind.ConsiderEverything2)) || //should be the binder for the type
fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios
if (firstDebugImports == null)
{
firstDebugImports = parentBinder.ImportChain;
}
parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol);
BoundFieldEqualsValue boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics);
boundInitializers.Add(boundInitializer);
break;
case ParameterSyntax parameterSyntax: // Initializer for a generated property based on record parameters
if (firstDebugImports == null)
{
if (binderFactory == null)
{
binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree);
}
firstDebugImports = binderFactory.GetBinder(parameterSyntax).ImportChain;
}
boundInitializers.Add(new BoundFieldEqualsValue(parameterSyntax, fieldSymbol, ImmutableArray<LocalSymbol>.Empty,
new BoundParameter(parameterSyntax,
((SynthesizedRecordPropertySymbol)fieldSymbol.AssociatedSymbol).BackingParameter).MakeCompilerGenerated()));
break;
default:
throw ExceptionUtilities.Unreachable;
}
Binder parentBinder = binderFactory.GetBinder(initializerNode);
Debug.Assert((parentBinder.ContainingMemberOrLambda is TypeSymbol containing && TypeSymbol.Equals(containing, fieldSymbol.ContainingType, TypeCompareKind.ConsiderEverything2)) || //should be the binder for the type
fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios
if (firstDebugImports == null)
{
firstDebugImports = parentBinder.ImportChain;
}
parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol);
BoundFieldEqualsValue boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics);
boundInitializers.Add(boundInitializer);
}
}
}
......
......@@ -3265,6 +3265,9 @@ public virtual BoundNode BindMethodBody(CSharpSyntaxNode syntax, DiagnosticBag d
{
switch (syntax)
{
case TypeDeclarationSyntax recordDecl:
return BindRecordConstructorBody(recordDecl);
case BaseMethodDeclarationSyntax method:
if (method.Kind() == SyntaxKind.ConstructorDeclaration)
{
......@@ -3311,6 +3314,15 @@ private BoundNode BindSimpleProgramCompilationUnit(CompilationUnitSyntax compila
expressionBody: null);
}
private BoundNode BindRecordConstructorBody(TypeDeclarationSyntax recordDecl)
{
return new BoundConstructorMethodBody(recordDecl,
locals: ImmutableArray<LocalSymbol>.Empty,
initializer: null,
blockBody: new BoundBlock(recordDecl, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<BoundStatement>.Empty).MakeCompilerGenerated(),
expressionBody: null);
}
private BoundNode BindConstructorBody(ConstructorDeclarationSyntax constructor, DiagnosticBag diagnostics)
{
if (constructor.Initializer == null && constructor.Body == null && constructor.ExpressionBody == null)
......@@ -3321,6 +3333,12 @@ private BoundNode BindConstructorBody(ConstructorDeclarationSyntax constructor,
Binder bodyBinder = this.GetBinder(constructor);
Debug.Assert(bodyBinder != null);
if (constructor.Initializer?.IsKind(SyntaxKind.ThisConstructorInitializer) != true &&
ContainingType.GetMembersUnordered().OfType<SynthesizedRecordConstructor>().Any())
{
Error(diagnostics, ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, constructor.Initializer?.ThisOrBaseKeyword ?? constructor.Identifier);
}
// Using BindStatement to bind block to make sure we are reusing results of partial binding in SemanticModel
return new BoundConstructorMethodBody(constructor,
bodyBinder.GetDeclaredLocalsForScope(constructor),
......
......@@ -156,6 +156,16 @@ public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax no
Visit(node.ExpressionBody, enclosing);
}
public override void VisitClassDeclaration(ClassDeclarationSyntax node)
{
// We get here for record's primary constructor
}
public override void VisitStructDeclaration(StructDeclarationSyntax node)
{
// We get here for record's primary constructor
}
public override void VisitDestructorDeclaration(DestructorDeclarationSyntax node)
{
Visit(node.Body);
......
......@@ -6241,4 +6241,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_UnexpectedArgumentList" xml:space="preserve">
<value>Unexpected argument list.</value>
</data>
<data name="ERR_UnexpectedOrMissingConstructorInitializerInRecord" xml:space="preserve">
<value>A constructor declared in a record with parameters must have 'this' constructor initializer.</value>
</data>
</root>
......@@ -976,7 +976,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);
!HasThisConstructorInitializer(methodSymbol) &&
!(methodSymbol is SynthesizedRecordCopyCtor); // 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)
......@@ -1641,11 +1642,11 @@ internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationSt
if (method is SourceMemberMethodSymbol sourceMethod)
{
CSharpSyntaxNode syntaxNode = sourceMethod.SyntaxNode;
var constructorSyntax = syntaxNode as ConstructorDeclarationSyntax;
// Static constructor can't have any this/base call
if (method.MethodKind == MethodKind.StaticConstructor &&
constructorSyntax?.Initializer != null)
syntaxNode is ConstructorDeclarationSyntax constructorSyntax &&
constructorSyntax.Initializer != null)
{
diagnostics.Add(
ErrorCode.ERR_StaticConstructorWithExplicitConstructorCall,
......@@ -1823,7 +1824,7 @@ private static void ReportCtorInitializerCycles(MethodSymbol method, BoundExpres
NamedTypeSymbol baseType = constructor.ContainingType.BaseTypeNoUseSiteDiagnostics;
SourceMemberMethodSymbol sourceConstructor = constructor as SourceMemberMethodSymbol;
Debug.Assert(((ConstructorDeclarationSyntax)sourceConstructor?.SyntaxNode)?.Initializer == null);
Debug.Assert(sourceConstructor?.SyntaxNode is TypeDeclarationSyntax || ((ConstructorDeclarationSyntax)sourceConstructor?.SyntaxNode)?.Initializer == null);
// The common case is that the type inherits directly from object.
// Also, we might be trying to generate a constructor for an entirely compiler-generated class such
......@@ -1871,11 +1872,25 @@ private static void ReportCtorInitializerCycles(MethodSymbol method, BoundExpres
}
else
{
// We have a ctor in source but no explicit constructor initializer. We can't just use the binder for the
// type containing the ctor because the ctor might be marked unsafe. Use the binder for the parameter list
// as an approximation - the extra symbols won't matter because there are no identifiers to bind.
BinderFactory binderFactory = compilation.GetBinderFactory(sourceConstructor.SyntaxTree);
outerBinder = compilation.GetBinderFactory(sourceConstructor.SyntaxTree).GetBinder(((ConstructorDeclarationSyntax)sourceConstructor.SyntaxNode).ParameterList);
switch (sourceConstructor.SyntaxNode)
{
case ConstructorDeclarationSyntax ctorDecl:
// We have a ctor in source but no explicit constructor initializer. We can't just use the binder for the
// type containing the ctor because the ctor might be marked unsafe. Use the binder for the parameter list
// as an approximation - the extra symbols won't matter because there are no identifiers to bind.
outerBinder = binderFactory.GetBinder(ctorDecl.ParameterList);
break;
case TypeDeclarationSyntax recordDecl:
outerBinder = binderFactory.GetInRecordBodyBinder(recordDecl);
break;
default:
throw ExceptionUtilities.Unreachable;
}
}
// wrap in ConstructorInitializerBinder for appropriate errors
......
......@@ -397,6 +397,18 @@ private SingleNamespaceOrTypeDeclaration VisitTypeDeclaration(TypeDeclarationSyn
var memberNames = GetNonTypeMemberNames(((Syntax.InternalSyntax.TypeDeclarationSyntax)(node.Green)).Members,
ref declFlags);
// A record with parameters at least has a primary constructor
if ((declFlags & SingleTypeDeclaration.TypeDeclarationFlags.HasAnyNontypeMembers) == 0)
{
switch (node)
{
case ClassDeclarationSyntax { ParameterList: { } }:
case StructDeclarationSyntax { ParameterList: { } }:
declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasAnyNontypeMembers;
break;
}
}
var modifiers = node.Modifiers.ToDeclarationModifiers(diagnostics: diagnostics);
return new SingleTypeDeclaration(
......
......@@ -1830,6 +1830,7 @@ internal enum ErrorCode
ERR_ContainingTypeMustDeriveFromWithReturnType = 8859,
ERR_WithMemberIsNotRecordProperty = 8860,
ERR_UnexpectedArgumentList = 8861,
ERR_UnexpectedOrMissingConstructorInitializerInRecord = 8862,
#endregion
......
......@@ -85,6 +85,12 @@ public override BoundStatement InstrumentFieldOrPropertyInitializer(BoundStateme
private static BoundStatement InstrumentFieldOrPropertyInitializer(BoundStatement rewritten, SyntaxNode syntax)
{
if (syntax.IsKind(SyntaxKind.Parameter))
{
// This is an initialization of a generated property based on record parameter.
return AddSequencePoint(rewritten);
}
Debug.Assert(syntax is { Parent: { Parent: { } } });
var grandparent = syntax.Parent.Parent;
switch (grandparent.Kind())
......
......@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class DebugInfoInjector
{
private BoundStatement AddSequencePoint(BoundStatement node)
private static BoundStatement AddSequencePoint(BoundStatement node)
{
return new BoundSequencePoint(node.Syntax, node);
}
......
......@@ -701,6 +701,13 @@ public override BoundNode VisitArrayAccess(BoundArrayAccess node)
internal static bool IsFieldOrPropertyInitializer(BoundStatement initializer)
{
var syntax = initializer.Syntax;
if (syntax.IsKind(SyntaxKind.Parameter))
{
// This is an initialization of a generated property based on record parameter.
return true;
}
if (syntax is ExpressionSyntax { Parent: { } parent } && parent.Kind() == SyntaxKind.EqualsValueClause) // Should be the initial value.
{
Debug.Assert(parent.Parent is { });
......
......@@ -18,7 +18,9 @@ internal struct FieldOrPropertyInitializer
internal readonly FieldSymbol FieldOpt;
/// <summary>
/// A reference to <see cref="EqualsValueClauseSyntax"/> or top-level <see cref="StatementSyntax"/> in script code.
/// A reference to <see cref="EqualsValueClauseSyntax"/>,
/// or top-level <see cref="StatementSyntax"/> in script code,
/// or <see cref="ParameterSyntax"/> for an initialization of a generated property based on record parameter.
/// </summary>
internal readonly SyntaxReference Syntax;
......@@ -30,11 +32,34 @@ internal struct FieldOrPropertyInitializer
public FieldOrPropertyInitializer(FieldSymbol fieldOpt, SyntaxNode syntax, int precedingInitializersLength)
{
Debug.Assert(syntax.IsKind(SyntaxKind.EqualsValueClause) && fieldOpt != null || syntax is StatementSyntax);
Debug.Assert(((syntax.IsKind(SyntaxKind.EqualsValueClause) || syntax.IsKind(SyntaxKind.Parameter)) && fieldOpt != null) || syntax is StatementSyntax);
FieldOpt = fieldOpt;
Syntax = syntax.GetReference();
PrecedingInitializersLength = precedingInitializersLength;
}
internal struct Builder
{
/// <summary>
/// The field being initialized (possibly a backing field of a property), or null if this is a top-level statement in script code.
/// </summary>
internal readonly FieldSymbol FieldOpt;
/// <summary>
/// A reference to <see cref="EqualsValueClauseSyntax"/>,
/// or top-level <see cref="StatementSyntax"/> in script code,
/// or <see cref="ParameterSyntax"/> for an initialization of a generated property based on record parameter.
/// </summary>
internal readonly SyntaxNode Syntax;
public Builder(FieldSymbol fieldOpt, SyntaxNode syntax)
{
Debug.Assert(((syntax.IsKind(SyntaxKind.EqualsValueClause) || syntax.IsKind(SyntaxKind.Parameter)) && fieldOpt != null) || syntax is StatementSyntax);
FieldOpt = fieldOpt;
Syntax = syntax;
}
}
}
}
......@@ -102,6 +102,7 @@ internal static int GetParameterCount(this Symbol member)
case SymbolKind.Property:
return ((PropertySymbol)member).ParameterCount;
case SymbolKind.Event:
case SymbolKind.Field:
return 0;
default:
throw ExceptionUtilities.UnexpectedValue(member.Kind);
......
......@@ -473,7 +473,7 @@ internal static OverriddenOrHiddenMembersResult MakeInterfaceOverriddenOrHiddenM
///
/// In incorrect or imported code, it is possible that both currTypeBestMatch and hiddenBuilder will be populated.
/// </remarks>
private static void FindOverriddenOrHiddenMembersInType(
internal static void FindOverriddenOrHiddenMembersInType(
Symbol member,
bool memberIsFromSomeCompilation,
NamedTypeSymbol memberContainingType,
......
......@@ -2,19 +2,14 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal sealed class SourceConstructorSymbol : SourceMemberMethodSymbol
internal sealed class SourceConstructorSymbol : SourceConstructorSymbolBase
{
private ImmutableArray<ParameterSymbol> _lazyParameters;
private TypeWithAnnotations _lazyReturnType;
private bool _lazyIsVararg;
private readonly bool _isExpressionBodied;
public static SourceConstructorSymbol CreateConstructorSymbol(
......@@ -27,12 +22,12 @@ internal sealed class SourceConstructorSymbol : SourceMemberMethodSymbol
}
private SourceConstructorSymbol(
SourceMemberContainerTypeSymbol containingType,
Location location,
ConstructorDeclarationSyntax syntax,
MethodKind methodKind,
DiagnosticBag diagnostics) :
base(containingType, syntax.GetReference(), ImmutableArray.Create(location), isIterator: SyntaxFacts.HasYieldOperations(syntax.Body))
SourceMemberContainerTypeSymbol containingType,
Location location,
ConstructorDeclarationSyntax syntax,
MethodKind methodKind,
DiagnosticBag diagnostics) :
base(containingType, location, syntax, methodKind, diagnostics)
{
bool hasBlockBody = syntax.Body != null;
_isExpressionBodied = !hasBlockBody && syntax.ExpressionBody != null;
......@@ -81,129 +76,20 @@ internal sealed class SourceConstructorSymbol : SourceMemberMethodSymbol
syntax.Body, syntax.ExpressionBody, syntax, diagnostics);
}
protected override void MethodChecks(DiagnosticBag diagnostics)
{
var syntax = GetSyntax();
var binderFactory = this.DeclaringCompilation.GetBinderFactory(syntax.SyntaxTree);
ParameterListSyntax parameterList = syntax.ParameterList;
// NOTE: if we asked for the binder for the body of the constructor, we'd risk a stack overflow because
// we might still be constructing the member list of the containing type. However, getting the binder
// for the parameters should be safe.
var bodyBinder = binderFactory.GetBinder(parameterList, syntax, this).WithContainingMemberOrLambda(this);
// Constraint checking for parameter and return types must be delayed until
// the method has been added to the containing type member list since
// evaluating the constraints may depend on accessing this method from
// the container (comparing this method to others to find overrides for
// instance). Constraints are checked in AfterAddingTypeMembersChecks.
var signatureBinder = bodyBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this);
SyntaxToken arglistToken;
_lazyParameters = ParameterHelpers.MakeParameters(
signatureBinder, this, parameterList, out arglistToken,
allowRefOrOut: true,
allowThis: false,
addRefReadOnlyModifier: false,
diagnostics: diagnostics);
_lazyIsVararg = (arglistToken.Kind() == SyntaxKind.ArgListKeyword);
_lazyReturnType = TypeWithAnnotations.Create(bodyBinder.GetSpecialType(SpecialType.System_Void, diagnostics, syntax));
var location = this.Locations[0];
if (MethodKind == MethodKind.StaticConstructor && (_lazyParameters.Length != 0))
{
diagnostics.Add(ErrorCode.ERR_StaticConstParam, location, this);
}
this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics);
if (_lazyIsVararg && (IsGenericMethod || ContainingType.IsGenericType || _lazyParameters.Length > 0 && _lazyParameters[_lazyParameters.Length - 1].IsParams))
{
diagnostics.Add(ErrorCode.ERR_BadVarargs, location);
}
}
internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics)
{
base.AfterAddingTypeMembersChecks(conversions, diagnostics);
var compilation = DeclaringCompilation;
ParameterHelpers.EnsureIsReadOnlyAttributeExists(compilation, Parameters, diagnostics, modifyCompilation: true);
ParameterHelpers.EnsureNativeIntegerAttributeExists(compilation, Parameters, diagnostics, modifyCompilation: true);
ParameterHelpers.EnsureNullableAttributeExists(compilation, this, Parameters, diagnostics, modifyCompilation: true);
foreach (var parameter in this.Parameters)
{
parameter.Type.CheckAllConstraints(compilation, conversions, parameter.Locations[0], diagnostics);
}
}
internal ConstructorDeclarationSyntax GetSyntax()
{
Debug.Assert(syntaxReferenceOpt != null);
return (ConstructorDeclarationSyntax)syntaxReferenceOpt.GetSyntax();
}
public override bool IsVararg
{
get
{
LazyMethodChecks();
return _lazyIsVararg;
}
}
public override bool IsImplicitlyDeclared
{
get
{
return base.IsImplicitlyDeclared;
}
}
internal override int ParameterCount
{
get
{
if (!_lazyParameters.IsDefault)
{
return _lazyParameters.Length;
}
return GetSyntax().ParameterList.ParameterCount;
}
}
public override ImmutableArray<ParameterSymbol> Parameters
{
get
{
LazyMethodChecks();
return _lazyParameters;
}
}
public override ImmutableArray<TypeParameterSymbol> TypeParameters
{
get { return ImmutableArray<TypeParameterSymbol>.Empty; }
}
public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses()
=> ImmutableArray<TypeParameterConstraintClause>.Empty;
public override RefKind RefKind
protected override ParameterListSyntax GetParameterList()
{
get { return RefKind.None; }
return GetSyntax().ParameterList;
}
public override TypeWithAnnotations ReturnTypeWithAnnotations
protected override CSharpSyntaxNode GetInitializer()
{
get
{
LazyMethodChecks();
return _lazyReturnType;
}
return GetSyntax().Initializer;
}
private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, MethodKind methodKind, bool hasBody, Location location, DiagnosticBag diagnostics, out bool modifierErrors)
......@@ -259,30 +145,11 @@ private void CheckModifiers(MethodKind methodKind, bool hasBody, Location locati
}
}
public override string Name
{
get { return this.IsStatic ? WellKnownMemberNames.StaticConstructorName : WellKnownMemberNames.InstanceConstructorName; }
}
internal override OneOrMany<SyntaxList<AttributeListSyntax>> GetAttributeDeclarations()
{
return OneOrMany.Create(((ConstructorDeclarationSyntax)this.SyntaxNode).AttributeLists);
}
internal override OneOrMany<SyntaxList<AttributeListSyntax>> GetReturnTypeAttributeDeclarations()
{
// constructors can't have return type attributes
return OneOrMany.Create(default(SyntaxList<AttributeListSyntax>));
}
protected override IAttributeTargetSymbol AttributeOwner
{
get
{
return base.AttributeOwner;
}
}
internal override bool IsExpressionBodied
{
get
......@@ -291,67 +158,22 @@ internal override bool IsExpressionBodied
}
}
internal override bool GenerateDebugInfo
{
get { return true; }
}
internal override int CalculateLocalSyntaxOffset(int position, SyntaxTree tree)
protected override bool IsWithinExpressionOrBlockBody(int position, out int offset)
{
Debug.Assert(position >= 0 && tree != null);
TextSpan span;
// local/lambda/closure defined within the body of the constructor:
ConstructorDeclarationSyntax ctorSyntax = GetSyntax();
if (tree == ctorSyntax.SyntaxTree)
{
if (ctorSyntax.Body?.Span.Contains(position) == true)
{
return position - ctorSyntax.Body.Span.Start;
}
else if (ctorSyntax.ExpressionBody?.Span.Contains(position) == true)
{
return position - ctorSyntax.ExpressionBody.Span.Start;
}
}
// closure in ctor initializer lifting its parameter(s) spans the constructor declaration:
if (position == ctorSyntax.SpanStart)
if (ctorSyntax.Body?.Span.Contains(position) == true)
{
// Use a constant that is distinct from any other syntax offset.
// -1 works since a field initializer and a constructor declaration header can't squeeze into a single character.
return -1;
offset = position - ctorSyntax.Body.Span.Start;
return true;
}
// lambdas in ctor initializer:
int ctorInitializerLength;
var ctorInitializer = ctorSyntax.Initializer;
if (tree == ctorInitializer?.SyntaxTree)
{
span = ctorInitializer.Span;
ctorInitializerLength = span.Length;
if (span.Contains(position))
{
return -ctorInitializerLength + (position - span.Start);
}
}
else
{
ctorInitializerLength = 0;
}
// lambdas in field/property initializers:
int syntaxOffset;
var containingType = (SourceNamedTypeSymbol)this.ContainingType;
if (containingType.TryCalculateSyntaxOffsetOfPositionInInitializer(position, tree, this.IsStatic, ctorInitializerLength, out syntaxOffset))
else if (ctorSyntax.ExpressionBody?.Span.Contains(position) == true)
{
return syntaxOffset;
offset = position - ctorSyntax.ExpressionBody.Span.Start;
return true;
}
// we haven't found the constructor part that declares the variable:
throw ExceptionUtilities.Unreachable;
offset = -1;
return false;
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal abstract class SourceConstructorSymbolBase : SourceMemberMethodSymbol
{
protected ImmutableArray<ParameterSymbol> _lazyParameters;
private TypeWithAnnotations _lazyReturnType;
private bool _lazyIsVararg;
protected SourceConstructorSymbolBase(
SourceMemberContainerTypeSymbol containingType,
Location location,
CSharpSyntaxNode syntax,
MethodKind methodKind,
DiagnosticBag diagnostics)
: base(containingType, syntax.GetReference(), ImmutableArray.Create(location), SyntaxFacts.HasYieldOperations(syntax))
{
Debug.Assert(syntax.IsKind(SyntaxKind.ConstructorDeclaration) || syntax.IsKind(SyntaxKind.ClassDeclaration) || syntax.IsKind(SyntaxKind.StructDeclaration));
}
protected sealed override void MethodChecks(DiagnosticBag diagnostics)
{
var syntax = (CSharpSyntaxNode)syntaxReferenceOpt.GetSyntax();
var binderFactory = this.DeclaringCompilation.GetBinderFactory(syntax.SyntaxTree);
ParameterListSyntax parameterList = GetParameterList();
// NOTE: if we asked for the binder for the body of the constructor, we'd risk a stack overflow because
// we might still be constructing the member list of the containing type. However, getting the binder
// for the parameters should be safe.
var bodyBinder = binderFactory.GetBinder(parameterList, syntax, this).WithContainingMemberOrLambda(this);
// Constraint checking for parameter and return types must be delayed until
// the method has been added to the containing type member list since
// evaluating the constraints may depend on accessing this method from
// the container (comparing this method to others to find overrides for
// instance). Constraints are checked in AfterAddingTypeMembersChecks.
var signatureBinder = bodyBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this);
SyntaxToken arglistToken;
_lazyParameters = ParameterHelpers.MakeParameters(
signatureBinder, this, parameterList, out arglistToken,
allowRefOrOut: true,
allowThis: false,
addRefReadOnlyModifier: false,
diagnostics: diagnostics);
_lazyIsVararg = (arglistToken.Kind() == SyntaxKind.ArgListKeyword);
_lazyReturnType = TypeWithAnnotations.Create(bodyBinder.GetSpecialType(SpecialType.System_Void, diagnostics, syntax));
var location = this.Locations[0];
if (MethodKind == MethodKind.StaticConstructor && (_lazyParameters.Length != 0))
{
diagnostics.Add(ErrorCode.ERR_StaticConstParam, location, this);
}
this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics);
if (_lazyIsVararg && (IsGenericMethod || ContainingType.IsGenericType || _lazyParameters.Length > 0 && _lazyParameters[_lazyParameters.Length - 1].IsParams))
{
diagnostics.Add(ErrorCode.ERR_BadVarargs, location);
}
}
protected abstract ParameterListSyntax GetParameterList();
internal sealed override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics)
{
base.AfterAddingTypeMembersChecks(conversions, diagnostics);
var compilation = DeclaringCompilation;
ParameterHelpers.EnsureIsReadOnlyAttributeExists(compilation, Parameters, diagnostics, modifyCompilation: true);
ParameterHelpers.EnsureNativeIntegerAttributeExists(compilation, Parameters, diagnostics, modifyCompilation: true);
ParameterHelpers.EnsureNullableAttributeExists(compilation, this, Parameters, diagnostics, modifyCompilation: true);
foreach (var parameter in this.Parameters)
{
parameter.Type.CheckAllConstraints(compilation, conversions, parameter.Locations[0], diagnostics);
}
}
public sealed override bool IsVararg
{
get
{
LazyMethodChecks();
return _lazyIsVararg;
}
}
public sealed override bool IsImplicitlyDeclared
{
get
{
return base.IsImplicitlyDeclared;
}
}
internal sealed override int ParameterCount
{
get
{
if (!_lazyParameters.IsDefault)
{
return _lazyParameters.Length;
}
return GetParameterList().ParameterCount;
}
}
public sealed override ImmutableArray<ParameterSymbol> Parameters
{
get
{
LazyMethodChecks();
return _lazyParameters;
}
}
public sealed override ImmutableArray<TypeParameterSymbol> TypeParameters
{
get { return ImmutableArray<TypeParameterSymbol>.Empty; }
}
public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses()
=> ImmutableArray<TypeParameterConstraintClause>.Empty;
public override RefKind RefKind
{
get { return RefKind.None; }
}
public sealed override TypeWithAnnotations ReturnTypeWithAnnotations
{
get
{
LazyMethodChecks();
return _lazyReturnType;
}
}
public sealed override string Name
{
get { return this.IsStatic ? WellKnownMemberNames.StaticConstructorName : WellKnownMemberNames.InstanceConstructorName; }
}
internal sealed override OneOrMany<SyntaxList<AttributeListSyntax>> GetReturnTypeAttributeDeclarations()
{
// constructors can't have return type attributes
return OneOrMany.Create(default(SyntaxList<AttributeListSyntax>));
}
protected sealed override IAttributeTargetSymbol AttributeOwner
{
get
{
return base.AttributeOwner;
}
}
internal sealed override bool GenerateDebugInfo
{
get { return true; }
}
internal sealed override int CalculateLocalSyntaxOffset(int position, SyntaxTree tree)
{
Debug.Assert(position >= 0 && tree != null);
TextSpan span;
// local/lambda/closure defined within the body of the constructor:
var ctorSyntax = (CSharpSyntaxNode)syntaxReferenceOpt.GetSyntax();
if (tree == ctorSyntax.SyntaxTree)
{
if (IsWithinExpressionOrBlockBody(position, out int offset))
{
return offset;
}
// closure in ctor initializer lifting its parameter(s) spans the constructor declaration:
if (position == ctorSyntax.SpanStart)
{
// Use a constant that is distinct from any other syntax offset.
// -1 works since a field initializer and a constructor declaration header can't squeeze into a single character.
return -1;
}
}
// lambdas in ctor initializer:
int ctorInitializerLength;
var ctorInitializer = GetInitializer();
if (tree == ctorInitializer?.SyntaxTree)
{
span = ctorInitializer.Span;
ctorInitializerLength = span.Length;
if (span.Contains(position))
{
return -ctorInitializerLength + (position - span.Start);
}
}
else
{
ctorInitializerLength = 0;
}
// lambdas in field/property initializers:
int syntaxOffset;
var containingType = (SourceNamedTypeSymbol)this.ContainingType;
if (containingType.TryCalculateSyntaxOffsetOfPositionInInitializer(position, tree, this.IsStatic, ctorInitializerLength, out syntaxOffset))
{
return syntaxOffset;
}
// we haven't found the constructor part that declares the variable:
throw ExceptionUtilities.Unreachable;
}
protected abstract CSharpSyntaxNode GetInitializer();
protected abstract bool IsWithinExpressionOrBlockBody(int position, out int offset);
}
}
......@@ -51,6 +51,8 @@ protected SourceMethodSymbolWithAttributes(SyntaxReference syntaxReferenceOpt)
return (CSharpSyntaxNode?)localFunction.Body ?? localFunction.ExpressionBody;
case CompilationUnitSyntax _ when this is SynthesizedSimpleProgramEntryPointSymbol entryPoint:
return (CSharpSyntaxNode)entryPoint.ReturnTypeSyntax;
case TypeDeclarationSyntax recordDecl:
return recordDecl;
default:
return null;
}
......
......@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
......
......@@ -5,59 +5,80 @@
#nullable enable
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal sealed class SynthesizedRecordConstructor : SynthesizedInstanceConstructor
internal sealed class SynthesizedRecordConstructor : SourceConstructorSymbolBase
{
public override ImmutableArray<ParameterSymbol> Parameters { get; }
public SynthesizedRecordConstructor(
SourceMemberContainerTypeSymbol containingType,
Binder parameterBinder,
ParameterListSyntax parameterList,
DiagnosticBag diagnostics)
: base(containingType)
{
Parameters = ParameterHelpers.MakeParameters(
parameterBinder,
this,
parameterList,
out _,
diagnostics,
allowRefOrOut: true,
allowThis: false,
addRefReadOnlyModifier: false);
}
internal override LexicalSortKey GetLexicalSortKey()
{
// We need a separate sort key because struct records will have two synthesized
// constructors: the record constructor, and the parameterless constructor
return LexicalSortKey.SynthesizedRecordCtor;
}
internal override void GenerateMethodBodyStatements(SyntheticBoundNodeFactory F, ArrayBuilder<BoundStatement> statements, DiagnosticBag diagnostics)
{
// Write assignments to backing fields
//
// {
// this.backingField1 = arg1
// ...
// this.backingFieldN = argN
// }
var containing = (SourceMemberContainerTypeSymbol)ContainingType;
foreach (var param in Parameters)
SourceMemberContainerTypeSymbol containingType,
TypeDeclarationSyntax syntax,
DiagnosticBag diagnostics) :
base(containingType, GetParameterList(syntax).GetLocation(), syntax, MethodKind.Constructor, diagnostics)
{
Debug.Assert(syntax.IsKind(SyntaxKind.ClassDeclaration) || syntax.IsKind(SyntaxKind.StructDeclaration));
this.MakeFlags(MethodKind.Constructor, DeclarationModifiers.Public, returnsVoid: true, isExtensionMethod: false);
}
internal TypeDeclarationSyntax GetSyntax()
{
Debug.Assert(syntaxReferenceOpt != null);
return (TypeDeclarationSyntax)syntaxReferenceOpt.GetSyntax();
}
protected override ParameterListSyntax GetParameterList()
{
return GetParameterList(GetSyntax());
}
private static ParameterListSyntax GetParameterList(TypeDeclarationSyntax syntax)
{
switch (syntax)
{
var members = containing.GetMembers(param.Name);
if (members.Length == 1 && members[0] is SynthesizedRecordPropertySymbol prop)
{
var field = prop.BackingField;
statements.Add(F.Assignment(F.Field(F.This(), field), F.Parameter(param)));
}
case ClassDeclarationSyntax classDecl:
return classDecl.ParameterList!;
case StructDeclarationSyntax structDecl:
return structDecl.ParameterList!;
default:
throw ExceptionUtilities.Unreachable;
}
}
protected override CSharpSyntaxNode? GetInitializer()
{
var baseTypeSyntax = GetSyntax().BaseList?.Types.FirstOrDefault() as SimpleBaseTypeSyntax;
if (baseTypeSyntax?.ArgumentList is object)
{
return baseTypeSyntax;
}
return null;
}
internal override bool IsExpressionBodied
{
get
{
return false;
}
}
protected override bool IsWithinExpressionOrBlockBody(int position, out int offset)
{
offset = -1;
return false;
}
internal override ExecutableCodeBinder TryGetBodyBinder(BinderFactory? binderFactoryOpt = null, bool ignoreAccessibility = false)
{
TypeDeclarationSyntax typeDecl = GetSyntax();
InMethodBinder result = (binderFactoryOpt ?? this.DeclaringCompilation.GetBinderFactory(typeDecl.SyntaxTree)).GetRecordConstructorInMethodBinder(this);
return new ExecutableCodeBinder(SyntaxNode, this, result.WithAdditionalFlags(ignoreAccessibility ? BinderFlags.IgnoreAccessibility : BinderFlags.None));
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
......@@ -10,7 +9,6 @@
using System.Collections.Immutable;
using System.Reflection;
using Microsoft.Cci;
using Microsoft.CodeAnalysis.PooledObjects;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
......@@ -118,4 +116,4 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
F.CloseMethod(F.Return(F.Literal(0)));
}
}
}
\ No newline at end of file
}
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
......@@ -20,7 +20,6 @@ internal sealed class SynthesizedRecordObjEquals : SynthesizedInstanceMethodSymb
public override ImmutableArray<ParameterSymbol> Parameters { get; }
public SynthesizedRecordObjEquals(NamedTypeSymbol containingType, MethodSymbol typedRecordEquals)
{
_typedRecordEquals = typedRecordEquals;
......@@ -152,4 +151,4 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
F.CloseMethod(F.Block(ImmutableArray.Create<BoundStatement>(F.Return(expression))));
}
}
}
\ No newline at end of file
}
......@@ -2,17 +2,14 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection;
using System.Text;
using Microsoft.Cci;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
......@@ -38,11 +35,13 @@ internal sealed class SynthesizedRecordPropertySymbol : SourceOrRecordPropertySy
GeneratedNames.MakeBackingFieldName(name),
isReadOnly: true,
isStatic: false,
hasInitializer: backingParameter.HasExplicitDefaultValue);
hasInitializer: true);
GetMethod = new GetAccessorSymbol(this, name);
SetMethod = new InitAccessorSymbol(this, name, diagnostics);
}
public ParameterSymbol BackingParameter => _backingParameter;
internal override bool IsAutoProperty => true;
public override RefKind RefKind => RefKind.None;
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">{0}: Nejde zadat třídu omezení a zároveň omezení unmanaged.</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">"{0}": Eine Einschränkungsklasse kann nicht gleichzeitig mit einer unmanaged-Einschränkung angegeben werden.</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">"{0}": no se puede especificar a la vez una clase de restricción y la restricción "unmanaged"</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}' : impossible de spécifier à la fois une classe de contrainte et la contrainte 'unmanaged'</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': non è possibile specificare sia una classe constraint che il vincolo 'unmanaged'</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': 制約クラスと 'unmanaged' 制約の両方を指定することはできません</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': constraint 클래스와 'unmanaged' 제약 조건을 둘 다 지정할 수는 없습니다.</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">„{0}”: nie można jednocześnie określić klasy ograniczenia i ograniczenia „unmanaged”</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': não é possível especificar uma classe de restrição e a restrição 'unmanaged'</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">"{0}": невозможно одновременно задать класс ограничения и ограничение "unmanaged"</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': hem bir kısıtlama sınıfı hem de 'unmanaged' kısıtlaması belirtilemez</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">“{0}”: 不能既指定约束类又指定 “unmanaged” 约束</target>
......
......@@ -712,6 +712,11 @@
<target state="new">Unexpected argument list.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnexpectedOrMissingConstructorInitializerInRecord">
<source>A constructor declared in a record with parameters must have 'this' constructor initializer.</source>
<target state="new">A constructor declared in a record with parameters must have 'this' constructor initializer.</target>
<note />
</trans-unit>
<trans-unit id="ERR_UnmanagedBoundWithClass">
<source>'{0}': cannot specify both a constraint class and the 'unmanaged' constraint</source>
<target state="translated">'{0}': 不可在指定條件約束類型的同時,又指定 'unmanaged' 條件約束</target>
......
......@@ -102,7 +102,12 @@ public void RecordExistingConstructor01()
{
}
}");
comp.VerifyDiagnostics();
comp.VerifyDiagnostics(
// (4,12): error CS8862: A constructor declared in a record with parameters must have 'this' constructor initializer.
// public C(int a, int b) // overload
Diagnostic(ErrorCode.ERR_UnexpectedOrMissingConstructorInitializerInRecord, "C").WithLocation(4, 12)
);
var c = comp.GlobalNamespace.GetTypeMember("C");
var ctors = c.GetMembers(".ctor");
Assert.Equal(3, ctors.Length);
......@@ -660,12 +665,12 @@ .maxstack 2
}
[Fact]
public void RecordClone2()
public void RecordClone2_0()
{
var comp = CreateCompilation(@"
data class C(int x, int y)
{
public C(C other) { }
public C(C other) : this(other.x, other.y) { }
}");
comp.VerifyDiagnostics();
......@@ -691,15 +696,53 @@ .maxstack 1
");
verifier.VerifyIL("C..ctor(C)", @"
{
// Code size 7 (0x7)
.maxstack 1
// Code size 19 (0x13)
.maxstack 3
IL_0000: ldarg.0
IL_0001: call ""object..ctor()""
IL_0006: ret
IL_0001: ldarg.1
IL_0002: callvirt ""int C.x.get""
IL_0007: ldarg.1
IL_0008: callvirt ""int C.y.get""
IL_000d: call ""C..ctor(int, int)""
IL_0012: ret
}
");
}
[Fact]
[WorkItem(44781, "https://github.com/dotnet/roslyn/issues/44781")]
public void RecordClone2_1()
{
var comp = CreateCompilation(@"
data class 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)
);
}
[Fact]
[WorkItem(44781, "https://github.com/dotnet/roslyn/issues/44781")]
public void RecordClone2_2()
{
var comp = CreateCompilation(@"
data class 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)
);
}
[Fact]
[WorkItem(44782, "https://github.com/dotnet/roslyn/issues/44782")]
public void RecordClone3()
{
var comp = CreateCompilation(@"
......@@ -708,6 +751,7 @@ public void RecordClone3()
{
public event Action E;
public int Z;
public int W = 123;
}");
comp.VerifyDiagnostics();
......@@ -732,7 +776,7 @@ .maxstack 1
}");
verifier.VerifyIL("C..ctor(C)", @"
{
// Code size 55 (0x37)
// Code size 67 (0x43)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""object..ctor()""
......@@ -752,12 +796,17 @@ .maxstack 2
IL_002b: ldarg.1
IL_002c: ldfld ""int C.Z""
IL_0031: stfld ""int C.Z""
IL_0036: ret
}");
IL_0036: ldarg.0
IL_0037: ldarg.1
IL_0038: ldfld ""int C.W""
IL_003d: stfld ""int C.W""
IL_0042: ret
}
");
}
[Fact]
public void RecordClone4()
public void RecordClone4_0()
{
var comp = CreateCompilation(@"
using System;
......@@ -767,6 +816,12 @@ public void RecordClone4()
public int Z;
}");
comp.VerifyDiagnostics(
// (3,21): error CS0171: Field 'S.E' must be fully assigned before control is returned to the caller
// public data struct S(int x, int y)
Diagnostic(ErrorCode.ERR_UnassignedThis, "(int x, int y)").WithArguments("S.E").WithLocation(3, 21),
// (3,21): error CS0171: Field 'S.Z' must be fully assigned before control is returned to the caller
// public data struct S(int x, int y)
Diagnostic(ErrorCode.ERR_UnassignedThis, "(int x, int y)").WithArguments("S.Z").WithLocation(3, 21),
// (5,25): warning CS0067: The event 'S.E' is never used
// public event Action E;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("S.E").WithLocation(5, 25)
......@@ -781,39 +836,29 @@ public void RecordClone4()
var ctor = (MethodSymbol)s.GetMembers(".ctor")[1];
Assert.Equal(1, ctor.ParameterCount);
Assert.True(ctor.Parameters[0].Type.Equals(s, TypeCompareKind.ConsiderEverything));
}
var verifier = CompileAndVerify(comp, verify: Verification.Fails);
verifier.VerifyIL("S." + WellKnownMemberNames.CloneMethodName, @"
{
// Code size 12 (0xc)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldobj ""S""
IL_0006: newobj ""S..ctor(S)""
IL_000b: ret
}");
verifier.VerifyIL("S..ctor(S)", @"
[Fact]
public void RecordClone4_1()
{
var comp = CreateCompilation(@"
using System;
public data struct S(int x, int y)
{
// Code size 49 (0x31)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldfld ""int S.<x>k__BackingField""
IL_0007: stfld ""int S.<x>k__BackingField""
IL_000c: ldarg.0
IL_000d: ldarg.1
IL_000e: ldfld ""int S.<y>k__BackingField""
IL_0013: stfld ""int S.<y>k__BackingField""
IL_0018: ldarg.0
IL_0019: ldarg.1
IL_001a: ldfld ""System.Action S.E""
IL_001f: stfld ""System.Action S.E""
IL_0024: ldarg.0
IL_0025: ldarg.1
IL_0026: ldfld ""int S.Z""
IL_002b: stfld ""int S.Z""
IL_0030: ret
public event Action E = null;
public int Z = 0;
}");
comp.VerifyDiagnostics(
// (5,25): error CS0573: 'S': cannot have instance property or field initializers in structs
// public event Action E = null;
Diagnostic(ErrorCode.ERR_FieldInitializerInStruct, "E").WithArguments("S").WithLocation(5, 25),
// (5,25): warning CS0414: The field 'S.E' is assigned but its value is never used
// public event Action E = null;
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "E").WithArguments("S.E").WithLocation(5, 25),
// (6,16): error CS0573: 'S': cannot have instance property or field initializers in structs
// public int Z = 0;
Diagnostic(ErrorCode.ERR_FieldInitializerInStruct, "Z").WithArguments("S").WithLocation(6, 16)
);
}
[Fact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册