Skip to content

Commit

Permalink
Partial properties: merging declarations and emit of simple cases (#7…
Browse files Browse the repository at this point in the history
  • Loading branch information
RikkiGibson authored May 1, 2024
1 parent 1bf2361 commit c3f13e3
Show file tree
Hide file tree
Showing 31 changed files with 1,749 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ public override Binder VisitAccessorDeclaration(AccessorDeclarationSyntax parent
if ((object)propertySymbol != null)
{
accessor = (parent.Kind() == SyntaxKind.GetAccessorDeclaration) ? propertySymbol.GetMethod : propertySymbol.SetMethod;
// PROTOTYPE(partial-properties): check if a property with no accessors could fail this assertion, in which case we should either adjust the assertion or remove it.
Debug.Assert(accessor is not null || parent.HasErrors);
}
break;
}
Expand Down Expand Up @@ -585,18 +587,25 @@ bool checkSymbol(Symbol sym, TextSpan memberSpan, SymbolKind kind, out Symbol re
return false;
}

if (sym.Kind == SymbolKind.Method)
if (kind is SymbolKind.Method or SymbolKind.Property)
{
if (InSpan(sym.GetFirstLocation(), this.syntaxTree, memberSpan))
{
return true;
}

// If this is a partial method, the method represents the defining part,
// not the implementation (method.Locations includes both parts). If the
// span is in fact in the implementation, return that method instead.
var implementation = ((MethodSymbol)sym).PartialImplementationPart;
if ((object)implementation != null)
// If this is a partial member, the member represents the defining part,
// not the implementation (member.Locations includes both parts). If the
// span is in fact in the implementation, return that member instead.
if (sym switch
#pragma warning disable format
{
MethodSymbol method => (Symbol)method.PartialImplementationPart,
SourcePropertySymbol property => property.PartialImplementationPart,
_ => throw ExceptionUtilities.UnexpectedValue(sym)
}
#pragma warning restore format
is { } implementation)
{
if (InSpan(implementation.GetFirstLocation(), this.syntaxTree, memberSpan))
{
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 @@ -7929,4 +7929,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, and cannot be an auto-property.</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>
8 changes: 8 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2310,6 +2310,14 @@ internal enum ErrorCode
ERR_InterceptsLocationDataInvalidPosition = 9235,
INF_TooManyBoundLambdas = 9236,

// PROTOTYPE(partial-properties): pack
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
7 changes: 7 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2438,6 +2438,13 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_InterceptsLocationFileNotFound:
case ErrorCode.ERR_InterceptsLocationDataInvalidPosition:
case ErrorCode.INF_TooManyBoundLambdas:

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
Loading

0 comments on commit c3f13e3

Please sign in to comment.