Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial properties: merging declarations and emit of simple cases #72999

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 || parent.HasErrors);
RikkiGibson marked this conversation as resolved.
Show resolved Hide resolved
}
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)
333fred marked this conversation as resolved.
Show resolved Hide resolved
{
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))
RikkiGibson marked this conversation as resolved.
Show resolved Hide resolved
{
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 @@ -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</value>
</data>
<data name="ERR_PartialPropertyDuplicateImplementation" xml:space="preserve">
<value>A partial property may not have multiple implementing declarations</value>
333fred marked this conversation as resolved.
Show resolved Hide resolved
</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)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did consider introducing some new members on a common base type, or introducing an IPartialMemberSymbol interface or something similar. But ultimately I think extension methods with type tests is an appropriate level of abstraction for this feature.

I am meaning to add a debug assertion that these methods are only used with original definition symbols. I'll try and add a check for that in future PR.

RikkiGibson marked this conversation as resolved.
Show resolved Hide resolved
{
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