Skip to content

Commit

Permalink
Partial properties 1
Browse files Browse the repository at this point in the history
  • Loading branch information
RikkiGibson committed Apr 15, 2024
1 parent 839e1ab commit 2332072
Show file tree
Hide file tree
Showing 30 changed files with 1,173 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ public override Binder VisitAccessorDeclaration(AccessorDeclarationSyntax parent
if ((object)propertySymbol != null)
{
accessor = (parent.Kind() == SyntaxKind.GetAccessorDeclaration) ? propertySymbol.GetMethod : propertySymbol.SetMethod;
Debug.Assert(accessor is not null); // '_position' was within the accessor body, why weren't we able to get a symbol for the accessor?
}
break;
}
Expand Down Expand Up @@ -605,6 +606,27 @@ bool checkSymbol(Symbol sym, TextSpan memberSpan, SymbolKind kind, out Symbol re
}
}
}
else if (sym.Kind == SymbolKind.Property)
{
if (InSpan(sym.GetFirstLocation(), this.syntaxTree, memberSpan))
{
return true;
}

// If this is a partial property, the property represents the defining part,
// not the implementation (property.Locations includes both parts). If the
// span is in fact in the implementation, return that property instead.
var property = (SourcePropertySymbol)sym;
var implementation = property.IsPartialDefinition ? property.OtherPartOfPartial : property;
if ((object)implementation != null)
{
if (InSpan(implementation.GetFirstLocation(), this.syntaxTree, memberSpan))
{
result = implementation;
return true;
}
}
}
else if (InSpan(sym.Locations, this.syntaxTree, memberSpan))
{
return true;
Expand Down
20 changes: 19 additions & 1 deletion src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,7 @@
<value>Cannot implicitly convert type '{0}' to '{1}'. An explicit conversion exists (are you missing a cast?)</value>
</data>
<data name="ERR_PartialMisplaced" xml:space="preserve">
<value>The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type.</value>
<value>The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type.</value>
</data>
<data name="ERR_ImportedCircularBase" xml:space="preserve">
<value>Imported type '{0}' is invalid. It contains a circular base type dependency.</value>
Expand Down Expand Up @@ -7923,4 +7923,22 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_InterceptsLocationDataInvalidPosition" xml:space="preserve">
<value>The data argument to InterceptsLocationAttribute refers to an invalid position in file '{0}'.</value>
</data>
<data name="ERR_PartialPropertyMissingImplementation" xml:space="preserve">
<value>Partial property '{0}' must have an implementation part.</value>
</data>
<data name="ERR_PartialPropertyMissingDefinition" xml:space="preserve">
<value>Partial property '{0}' must have an definition part.</value>
</data>
<data name="ERR_PartialPropertyDuplicateDefinition" xml:space="preserve">
<value>A partial property may not have multiple defining declarations</value>
</data>
<data name="ERR_PartialPropertyDuplicateImplementation" xml:space="preserve">
<value>A partial property may not have multiple implementing declarations</value>
</data>
<data name="ERR_PartialPropertyMissingAccessor" xml:space="preserve">
<value>Property accessor '{0}' must be implemented because it is declared on the definition part</value>
</data>
<data name="ERR_PartialPropertyUnexpectedAccessor" xml:space="preserve">
<value>Property accessor '{0}' does not implement any accessor declared on the definition part</value>
</data>
</root>
7 changes: 7 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2309,6 +2309,13 @@ internal enum ErrorCode
ERR_InterceptsLocationFileNotFound = 9234,
ERR_InterceptsLocationDataInvalidPosition = 9235,

ERR_PartialPropertyMissingImplementation = 9300,
ERR_PartialPropertyMissingDefinition = 9301,
ERR_PartialPropertyDuplicateDefinition = 9302,
ERR_PartialPropertyDuplicateImplementation = 9303,
ERR_PartialPropertyMissingAccessor = 9304,
ERR_PartialPropertyUnexpectedAccessor = 9305,

#endregion

// Note: you will need to do the following after adding errors:
Expand Down
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2437,6 +2437,12 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_InterceptsLocationDuplicateFile:
case ErrorCode.ERR_InterceptsLocationFileNotFound:
case ErrorCode.ERR_InterceptsLocationDataInvalidPosition:
case ErrorCode.ERR_PartialPropertyMissingImplementation:
case ErrorCode.ERR_PartialPropertyMissingDefinition:
case ErrorCode.ERR_PartialPropertyDuplicateDefinition:
case ErrorCode.ERR_PartialPropertyDuplicateImplementation:
case ErrorCode.ERR_PartialPropertyMissingAccessor:
case ErrorCode.ERR_PartialPropertyUnexpectedAccessor:
return false;
default:
// NOTE: All error codes must be explicitly handled in this switch statement
Expand Down
22 changes: 14 additions & 8 deletions src/Compilers/CSharp/Portable/Symbols/MemberSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ internal static bool ShouldEmit(this MethodSymbol method)
}

// Don't emit partial methods without an implementation part.
if (method.IsPartialMethod() && method.PartialImplementationPart is null)
if (method.IsPartialMember() && method.PartialImplementationPart is null)
{
return false;
}
Expand Down Expand Up @@ -545,22 +545,28 @@ internal static bool IsExplicitInterfaceImplementation(this Symbol member)
}
}

internal static bool IsPartialMethod(this Symbol member)
internal static bool IsPartialMember(this Symbol member)
{
var sms = member as SourceMemberMethodSymbol;
return sms?.IsPartial == true;
return member
is SourceOrdinaryMethodSymbol { IsPartial: true }
or SourcePropertySymbol { IsPartial: true }
or SourcePropertyAccessorSymbol { IsPartial: true };
}

internal static bool IsPartialImplementation(this Symbol member)
{
var sms = member as SourceOrdinaryMethodSymbol;
return sms?.IsPartialImplementation == true;
return member
is SourceOrdinaryMethodSymbol { IsPartialImplementation: true }
or SourcePropertySymbol { IsPartialImplementation: true }
or SourcePropertyAccessorSymbol { IsPartialImplementation: true };
}

internal static bool IsPartialDefinition(this Symbol member)
{
var sms = member as SourceOrdinaryMethodSymbol;
return sms?.IsPartialDefinition == true;
return member
is SourceOrdinaryMethodSymbol { IsPartialDefinition: true }
or SourcePropertySymbol { IsPartialDefinition: true }
or SourcePropertyAccessorSymbol { IsPartialDefinition: true };
}

internal static bool ContainsTupleNames(this Symbol member)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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.

namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
/// <summary>
/// Implemented by non-type symbols that can be declared 'partial', such as methods, properties, and property accessors.
/// Note that property accessors cannot be independently marked 'partial', they inherit it from their containing property declaration.
/// </summary>
internal interface IPartialMemberSymbol // PROTOTYPE(partial-properties): not sure yet whether to try to use this abstraction
{
/// <summary>
/// If this is a partial declaration, returns the other part.
/// This does not return a valid value until InitializePartialMemberParts has been called.
/// </summary>
Symbol? OtherPartOfPartial { get; }

bool IsPartialDefinition { get; }

bool IsPartialImplementation { get; }
}
}
Loading

0 comments on commit 2332072

Please sign in to comment.