-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Records: override abstract inherited properties #45336
Changes from all commits
e22ea5e
e065ff0
d1f9199
942fae4
3af055e
8f43626
40c5f83
b9b5038
3028c82
d94b13e
03be993
c9af0db
7971a3b
63b0dae
7a0481b
697f85f
5d5316b
7f6fd4b
f852cf0
f29f2f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3065,26 +3065,32 @@ ImmutableArray<PropertySymbol> addProperties(ImmutableArray<ParameterSymbol> rec | |
int addedCount = 0; | ||
foreach (ParameterSymbol param in recordParameters) | ||
{ | ||
var property = new SynthesizedRecordPropertySymbol(this, param, diagnostics); | ||
_ = memberSignatures.TryGetValue(property, out var existingMember); | ||
existingMember ??= getInheritedMember(property, this); | ||
bool isInherited = false; | ||
var syntax = param.GetNonNullSyntaxNode(); | ||
var property = new SynthesizedRecordPropertySymbol(this, syntax, param, isOverride: false, diagnostics); | ||
if (!memberSignatures.TryGetValue(property, out var existingMember)) | ||
{ | ||
Debug.Assert(property.OverriddenOrHiddenMembers.OverriddenMembers.Length == 0); // property is not virtual and should not have overrides | ||
existingMember = property.OverriddenOrHiddenMembers.HiddenMembers.FirstOrDefault(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do we care if the hidden member is not a property? #Closed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Not currently we don't. We report an error if the property hides a distinct member. (That is existing behavior.) In reply to: 446540627 [](ancestors = 446540627) |
||
isInherited = true; | ||
} | ||
if (existingMember is null) | ||
{ | ||
existingOrAddedMembers.Add(property); | ||
members.Add(property); | ||
members.Add(property.GetMethod); | ||
members.Add(property.SetMethod); | ||
members.Add(property.BackingField); | ||
|
||
builder.InstanceInitializersForRecordDeclarationWithParameters.Insert(addedCount, new FieldOrPropertyInitializer.Builder(property.BackingField, paramList.Parameters[param.Ordinal])); | ||
addedCount++; | ||
addProperty(property); | ||
} | ||
else if (existingMember is PropertySymbol { IsStatic: false, GetMethod: { } } prop | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The current specification, that I think should be up to date given the time when the #44618 was created, and the rules stated in the issue disagree. The issue:
The specification:
Could you please reconcile the differences? This is not blocking #Resolved |
||
&& prop.TypeWithAnnotations.Equals(param.TypeWithAnnotations, TypeCompareKind.AllIgnoreOptions)) | ||
{ | ||
// There already exists a member corresponding to the candidate synthesized property. | ||
// The deconstructor is specified to simply assign from this property to the corresponding out parameter. | ||
existingOrAddedMembers.Add(prop); | ||
if (isInherited && prop.IsAbstract) | ||
{ | ||
addProperty(new SynthesizedRecordPropertySymbol(this, syntax, param, isOverride: true, diagnostics)); | ||
} | ||
else | ||
{ | ||
// Deconstruct() is specified to simply assign from this property to the corresponding out parameter. | ||
existingOrAddedMembers.Add(prop); | ||
} | ||
} | ||
else | ||
{ | ||
|
@@ -3094,6 +3100,18 @@ ImmutableArray<PropertySymbol> addProperties(ImmutableArray<ParameterSymbol> rec | |
param.TypeWithAnnotations, | ||
param.Name); | ||
} | ||
|
||
void addProperty(SynthesizedRecordPropertySymbol property) | ||
{ | ||
existingOrAddedMembers.Add(property); | ||
members.Add(property); | ||
members.Add(property.GetMethod); | ||
members.Add(property.SetMethod); | ||
members.Add(property.BackingField); | ||
|
||
builder.InstanceInitializersForRecordDeclarationWithParameters.Insert(addedCount, new FieldOrPropertyInitializer.Builder(property.BackingField, paramList.Parameters[param.Ordinal])); | ||
addedCount++; | ||
} | ||
} | ||
|
||
#if DEBUG | ||
|
@@ -3107,32 +3125,6 @@ ImmutableArray<PropertySymbol> addProperties(ImmutableArray<ParameterSymbol> rec | |
return existingOrAddedMembers.ToImmutableAndFree(); | ||
} | ||
|
||
static Symbol? getInheritedMember(Symbol symbol, NamedTypeSymbol type) | ||
{ | ||
while ((type = type.BaseTypeNoUseSiteDiagnostics) is object) | ||
{ | ||
OverriddenOrHiddenMembersHelpers.FindOverriddenOrHiddenMembersInType( | ||
symbol, | ||
memberIsFromSomeCompilation: true, | ||
memberContainingType: symbol.ContainingType, | ||
currType: type, | ||
out var bestMatch, | ||
out bool hasSameKindNonMatch, | ||
out var hiddenBuilder); | ||
if (hiddenBuilder is object) | ||
{ | ||
var result = hiddenBuilder[0]; | ||
hiddenBuilder.Free(); | ||
return result; | ||
} | ||
if (bestMatch is object) | ||
{ | ||
return bestMatch; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
void addObjectEquals(MethodSymbol thisEquals) | ||
{ | ||
var objEquals = new SynthesizedRecordObjEquals(this, thisEquals, memberOffset: members.Count, diagnostics); | ||
|
@@ -3149,23 +3141,9 @@ void addHashCode(PropertySymbol equalityContract) | |
} | ||
} | ||
|
||
static PropertySymbol? getInheritedEqualityContract(NamedTypeSymbol type) | ||
{ | ||
while ((type = type.BaseTypeNoUseSiteDiagnostics) is object) | ||
{ | ||
var members = type.GetMembers(SynthesizedRecordEqualityContractProperty.PropertyName); | ||
// https://github.com/dotnet/roslyn/issues/44903: Check explicit member has expected signature. | ||
if (members.FirstOrDefault(m => m is PropertySymbol property && property.ParameterCount == 0) is PropertySymbol property) | ||
{ | ||
return property; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
PropertySymbol addEqualityContract() | ||
{ | ||
var property = new SynthesizedRecordEqualityContractProperty(this, isOverride: getInheritedEqualityContract(this) is object); | ||
var property = new SynthesizedRecordEqualityContractProperty(this, isOverride: SynthesizedRecordClone.FindValidCloneMethod(BaseTypeNoUseSiteDiagnostics) is object); | ||
// https://github.com/dotnet/roslyn/issues/44903: Check explicit member has expected signature. | ||
if (!memberSignatures.ContainsKey(property)) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using SignatureOnlyPropertySymbol to check for an existing member. I am planning to switch all checks like that in this function to use SignatureOnly symbols. I think this will eliminate some overhead and will add some predictability in terms of what is happening and when. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems like a separable change.
In reply to: 446540258 [](ancestors = 446540258)