| File: Symbols\Synthesized\Records\SynthesizedRecordDeconstruct.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// 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 System.Linq; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed class SynthesizedRecordDeconstruct : SynthesizedRecordOrdinaryMethod { private readonly SynthesizedPrimaryConstructor _ctor; private readonly ImmutableArray<Symbol> _positionalMembers; public SynthesizedRecordDeconstruct( SourceMemberContainerTypeSymbol containingType, SynthesizedPrimaryConstructor ctor, ImmutableArray<Symbol> positionalMembers, int memberOffset) : base(containingType, WellKnownMemberNames.DeconstructMethodName, memberOffset, DeclarationModifiers.Public | (IsReadOnly(containingType, positionalMembers) ? DeclarationModifiers.ReadOnly : 0)) { Debug.Assert(positionalMembers.All(p => p is PropertySymbol { GetMethod: not null } or FieldSymbol)); _ctor = ctor; _positionalMembers = positionalMembers; } protected override (TypeWithAnnotations ReturnType, ImmutableArray<ParameterSymbol> Parameters) MakeParametersAndBindReturnType(BindingDiagnosticBag diagnostics) { var compilation = DeclaringCompilation; var location = ReturnTypeLocation; return (ReturnType: TypeWithAnnotations.Create(Binder.GetSpecialType(compilation, SpecialType.System_Void, location, diagnostics)), Parameters: _ctor.Parameters.SelectAsArray<ParameterSymbol, ImmutableArray<Location>, ParameterSymbol>( (param, locations) => new SourceSimpleParameterSymbol(owner: this, param.TypeWithAnnotations, param.Ordinal, RefKind.Out, param.Name, locations), arg: Locations)); } protected override int GetParameterCountFromSyntax() => _ctor.ParameterCount; internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { var F = new SyntheticBoundNodeFactory(this, ContainingType.GetNonNullSyntaxNode(), compilationState, diagnostics); if (ParameterCount != _positionalMembers.Length) { // There is a mismatch, an error was reported elsewhere F.CloseMethod(F.ThrowNull()); return; } var statementsBuilder = ArrayBuilder<BoundStatement>.GetInstance(_positionalMembers.Length + 1); for (int i = 0; i < _positionalMembers.Length; i++) { var parameter = Parameters[i]; var positionalMember = _positionalMembers[i]; var type = positionalMember switch { PropertySymbol property => property.Type, FieldSymbol field => field.Type, _ => throw ExceptionUtilities.Unreachable() }; if (!parameter.Type.Equals(type, TypeCompareKind.AllIgnoreOptions)) { // There is a mismatch, an error was reported elsewhere statementsBuilder.Free(); F.CloseMethod(F.ThrowNull()); return; } switch (positionalMember) { case PropertySymbol property: // parameter_i = property_i; statementsBuilder.Add(F.Assignment(F.Parameter(parameter), F.Property(F.This(), property))); break; case FieldSymbol field: // parameter_i = field_i; statementsBuilder.Add(F.Assignment(F.Parameter(parameter), F.Field(F.This(), field))); break; } } statementsBuilder.Add(F.Return()); F.CloseMethod(F.Block(statementsBuilder.ToImmutableAndFree())); } private static bool IsReadOnly(SourceMemberContainerTypeSymbol containingType, ImmutableArray<Symbol> positionalMembers) { return containingType.IsReadOnly || (containingType.IsRecordStruct && !positionalMembers.Any(static m => hasNonReadOnlyGetter(m))); static bool hasNonReadOnlyGetter(Symbol m) { if (m.Kind is SymbolKind.Property) { var property = (PropertySymbol)m; var getterMethod = property.GetMethod; return property.GetMethod is not null && !getterMethod.IsEffectivelyReadOnly; } return false; } } } }