-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Adding IsConst modreq on ref readonly signatures #19658
Changes from 2 commits
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 |
---|---|---|
|
@@ -1002,26 +1002,22 @@ public override ImmutableArray<MethodSymbol> ExplicitInterfaceImplementations | |
|
||
internal override DiagnosticInfo GetUseSiteDiagnostic() | ||
{ | ||
DiagnosticInfo result = null; | ||
|
||
if (!_packedFlags.IsUseSiteDiagnosticPopulated) | ||
{ | ||
DiagnosticInfo result = null; | ||
CalculateUseSiteDiagnostic(ref result); | ||
EnsureTypeParametersAreLoaded(ref result); | ||
return InitializeUseSiteDiagnostic(result); | ||
} | ||
|
||
var uncommonFields = _uncommonFields; | ||
if (uncommonFields == null) | ||
{ | ||
return null; | ||
result = InitializeUseSiteDiagnostic(result); | ||
} | ||
else | ||
{ | ||
var result = uncommonFields._lazyUseSiteDiagnostic; | ||
return CSDiagnosticInfo.IsEmpty(result) | ||
? InterlockedOperations.Initialize(ref uncommonFields._lazyUseSiteDiagnostic, null, CSDiagnosticInfo.EmptyErrorInfo) | ||
: result; | ||
result = _uncommonFields?._lazyUseSiteDiagnostic; | ||
} | ||
|
||
return CSDiagnosticInfo.IsEmpty(result) | ||
? InterlockedOperations.Initialize(ref _uncommonFields._lazyUseSiteDiagnostic, null, CSDiagnosticInfo.EmptyErrorInfo) | ||
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. Is |
||
: result; | ||
} | ||
|
||
private DiagnosticInfo InitializeUseSiteDiagnostic(DiagnosticInfo diagnostic) | ||
|
@@ -1033,7 +1029,7 @@ private DiagnosticInfo InitializeUseSiteDiagnostic(DiagnosticInfo diagnostic) | |
} | ||
|
||
_packedFlags.SetIsUseSiteDiagnosticPopulated(); | ||
return diagnostic; | ||
return _uncommonFields?._lazyUseSiteDiagnostic; | ||
} | ||
|
||
internal override ImmutableArray<string> GetAppliedConditionalSymbols() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,11 +52,16 @@ internal override Cci.PrimitiveTypeCode GetPrimitiveTypeCode(PEModuleSymbol modu | |
return type.PrimitiveTypeCode; | ||
} | ||
|
||
internal override bool IsVolatileModifierType(PEModuleSymbol moduleSymbol, TypeSymbol type) | ||
internal override bool IsAcceptedVolatileModifierType(PEModuleSymbol moduleSymbol, TypeSymbol type) | ||
{ | ||
return type.SpecialType == SpecialType.System_Runtime_CompilerServices_IsVolatile; | ||
} | ||
|
||
internal override bool IsAcceptedIsConstModifierType(TypeSymbol type) | ||
{ | ||
return type.IsWellKnownTypeIsConst(); | ||
} | ||
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. Comparing symbols by full name is probably not be the best way to do it. Looking up a better alternative. #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. Consider a similar scenario like 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. Unfortunately, no. Unless there is something I'm missing, In reply to: 117829472 [](ancestors = 117829472) 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. Perhaps the same approach as 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. 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. This seems simple enough to fix now vs. needing a PROTOTYPE comment to fix later. #Resolved 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.
Given that this is not a SpecialType, I think name comparison is the only right way to do that. If performance is a concern we can compare type name and namespace names separately, then calling ToDisplayString won't be needed. #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. If going with name comparing, should definitely compare namespace/type name parts separately. I think ToDisplay will concat them every time In reply to: 118063143 [](ancestors = 118063143) 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. 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. From what I tracked down, it ends up doing a lookup in In reply to: 117866143 [](ancestors = 117866143) 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. Could we simplify 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. Can you please explain? caching what? this is not doing lookup, but rather checking the passed symbol for full name equality. In reply to: 118763594 [](ancestors = 118763594) |
||
|
||
internal override TypeSymbol GetSZArrayTypeSymbol(PEModuleSymbol moduleSymbol, TypeSymbol elementType, ImmutableArray<ModifierInfo<TypeSymbol>> customModifiers) | ||
{ | ||
if (elementType is UnsupportedMetadataTypeSymbol) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,7 +63,7 @@ public static bool HasRefOrOutParameter(this PropertySymbol property) | |
{ | ||
foreach (ParameterSymbol param in property.Parameters) | ||
{ | ||
if (param.RefKind != RefKind.None) | ||
if (param.RefKind == RefKind.Ref || param.RefKind == RefKind.Out) | ||
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.
Did you add a test backing this change? Could you point to the test(s)? #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. Adding In reply to: 118061963 [](ancestors = 118061963) 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.
I couldn't find the test, what file it should be in? In reply to: 118609191 [](ancestors = 118609191,118061963) 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. File In reply to: 119789809 [](ancestors = 119789809,118609191,118061963) 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. Correction: In reply to: 120218968 [](ancestors = 120218968,119789809,118609191,118061963) |
||
{ | ||
return true; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,8 +35,7 @@ internal static void CopyMethodCustomModifiers( | |
// have already been compared. | ||
MethodSymbol constructedSourceMethod = sourceMethod.ConstructIfGeneric(destinationMethod.TypeArguments); | ||
|
||
customModifiers = CustomModifiersTuple.Create(constructedSourceMethod.ReturnTypeCustomModifiers, | ||
destinationMethod.ReturnsByRef ? constructedSourceMethod.RefCustomModifiers : ImmutableArray<CustomModifier>.Empty); | ||
customModifiers = CustomModifiersTuple.Create(constructedSourceMethod.ReturnTypeCustomModifiers, constructedSourceMethod.RefCustomModifiers); | ||
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.
What is the motivation behind this change? id doesn't look appropriate to me. #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. ReturnsByRef is an api that returns true for methods that return by reference. There is another API now (ReturnsByRefReadOnly) that needs copying as well. My understanding is that all such implementations should exactly duplicate their overridden methods (CLR-spec), which the new implementation is doing. In reply to: 118068064 [](ancestors = 118068064) 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.
Only when ref modifier is present, which might not be the case in error situations. If destination method is not ref returning, it shouldn't have RefCustomModifiers because they have nothing to modify. It is fine to adjust the condition, but it is incorrect to remove conditional logic altogether. #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. BTW, please add tests for these scenarios. #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. Will adjust to logic to only copy on ref and ref-readonly. Will add a test to make sure we produce an error when a non-ref method is trying to override a ref-method, and that the symbol we create for the child method has no modifiers. In reply to: 118421550 [](ancestors = 118421550) 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. This was marked as resolved, but I didn't notice the tests. The scenario would be when overriding method is not ref returning, but the overridden method is ref readonly returning. In reply to: 118421677 [](ancestors = 118421677) 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. Added In reply to: 119789256 [](ancestors = 119789256,118421677) |
||
|
||
parameters = CopyParameterCustomModifiers(constructedSourceMethod.Parameters, destinationMethod.Parameters, alsoCopyParamsModifier); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -167,6 +167,7 @@ private void MethodChecks(MethodDeclarationSyntax syntax, Binder withTypeParamsB | |
signatureBinder, this, syntax.ParameterList, out arglistToken, | ||
allowRefOrOut: true, | ||
allowThis: true, | ||
addIsConstModifier: IsVirtual || IsAbstract, | ||
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.
This should probably include checks for override and explicit implementation, those are virtual (in metadata terms) as well and the difference will be observable for cases when the target method cannot be found, etc. #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. |
||
diagnostics: diagnostics); | ||
|
||
_lazyIsVararg = (arglistToken.Kind() == SyntaxKind.ArgListKeyword); | ||
|
@@ -320,11 +321,19 @@ private void MethodChecks(MethodDeclarationSyntax syntax, Binder withTypeParamsB | |
|
||
if ((object)overriddenMethod != null) | ||
{ | ||
CustomModifierUtils.CopyMethodCustomModifiers(overriddenMethod, this, out _lazyReturnType, | ||
out _lazyCustomModifiers, | ||
CustomModifierUtils.CopyMethodCustomModifiers(overriddenMethod, this, out _lazyReturnType, | ||
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.
Is it Ok to end up without IsCons modifier for overriding case (overriding method is technically virtual)? Do we have a test for scenario like that? #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. My understanding is that the overriding method should always copy the parent's modifiers (for CLR to consider it as an override). And if the overridden method is a C# 7.1 virtual method with a ref-readonly parameter or a return type, then it will have this modifier. In reply to: 118078081 [](ancestors = 118078081) 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.
For proper overriding we should match modifiers exactly. I guess we have to decide whether it is fine to override without modifier, or should that be an error. #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. will keep the current behavior, and add a test to assert it. In reply to: 118420724 [](ancestors = 118420724) |
||
out _lazyCustomModifiers, | ||
out _lazyParameters, alsoCopyParamsModifier: true); | ||
} | ||
} | ||
else if (_refKind == RefKind.RefReadOnly && (IsVirtual || IsAbstract)) | ||
{ | ||
var isConstType = withTypeParamsBinder.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsConst, diagnostics, syntax.ReturnType); | ||
|
||
_lazyCustomModifiers = CustomModifiersTuple.Create( | ||
typeCustomModifiers: ImmutableArray<CustomModifier>.Empty, | ||
refCustomModifiers: ImmutableArray.Create(CSharpCustomModifier.CreateRequired(isConstType))); | ||
} | ||
} | ||
else if ((object)_explicitInterfaceType != null) | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -273,6 +273,14 @@ private SourcePropertySymbol( | |
_lazyParameters = CustomModifierUtils.CopyParameterCustomModifiers(overriddenOrImplementedProperty.Parameters, _lazyParameters, alsoCopyParamsModifier: isOverride); | ||
} | ||
} | ||
else if (_refKind == RefKind.RefReadOnly && (IsVirtual || IsAbstract)) | ||
{ | ||
var isConstType = bodyBinder.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsConst, diagnostics, syntax.Type); | ||
|
||
_customModifiers = CustomModifiersTuple.Create( | ||
ImmutableArray<CustomModifier>.Empty, | ||
ImmutableArray.Create(CSharpCustomModifier.CreateRequired(isConstType))); | ||
} | ||
|
||
if (!hasAccessorList) | ||
{ | ||
|
@@ -775,7 +783,7 @@ private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, bool isExp | |
} | ||
|
||
private static ImmutableArray<ParameterSymbol> MakeParameters( | ||
Binder binder, SourcePropertySymbol owner, BaseParameterListSyntax parameterSyntaxOpt, DiagnosticBag diagnostics) | ||
Binder binder, SourcePropertySymbol owner, BaseParameterListSyntax parameterSyntaxOpt, DiagnosticBag diagnostics, bool addIsConstModifier) | ||
{ | ||
if (parameterSyntaxOpt == null) | ||
{ | ||
|
@@ -792,6 +800,7 @@ private static ImmutableArray<ParameterSymbol> MakeParameters( | |
binder, owner, parameterSyntaxOpt, out arglistToken, | ||
allowRefOrOut: false, | ||
allowThis: false, | ||
addIsConstModifier: addIsConstModifier, | ||
diagnostics: diagnostics); | ||
|
||
if (arglistToken.Kind() != SyntaxKind.None) | ||
|
@@ -1388,7 +1397,7 @@ private TypeSymbol ComputeType(Binder binder, BasePropertyDeclarationSyntax synt | |
private ImmutableArray<ParameterSymbol> ComputeParameters(Binder binder, BasePropertyDeclarationSyntax syntax, DiagnosticBag diagnostics) | ||
{ | ||
var parameterSyntaxOpt = GetParameterListSyntax(syntax); | ||
var parameters = MakeParameters(binder, this, parameterSyntaxOpt, diagnostics); | ||
var parameters = MakeParameters(binder, this, parameterSyntaxOpt, diagnostics, addIsConstModifier: IsVirtual || IsAbstract); | ||
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.
Same comment as for methods. #Closed |
||
HashSet<DiagnosticInfo> useSiteDiagnostics = null; | ||
|
||
foreach (ParameterSymbol param in parameters) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -406,5 +406,40 @@ internal static void GetTypeOrReturnType(this Symbol symbol, out RefKind refKind | |
throw ExceptionUtilities.UnexpectedValue(symbol.Kind); | ||
} | ||
} | ||
|
||
internal static bool IsWellKnownTypeIsConst(this ISymbol symbol) | ||
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.
Does it have to be an extension on ISymbol? Could it extend INamedTypeSymbol instead? #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. It can use In reply to: 119750837 [](ancestors = 119750837) |
||
{ | ||
if (symbol is NamedTypeSymbol typeSymbol) | ||
{ | ||
if (typeSymbol.Name != "IsConst" || typeSymbol.ContainingType != null) | ||
{ | ||
return false; | ||
} | ||
|
||
var compilerServicesNamespace = typeSymbol.ContainingNamespace; | ||
if (compilerServicesNamespace?.Name != "CompilerServices") | ||
{ | ||
return false; | ||
} | ||
|
||
var runtimeNamespace = compilerServicesNamespace.ContainingNamespace; | ||
if (runtimeNamespace?.Name != "Runtime") | ||
{ | ||
return false; | ||
} | ||
|
||
var systemNamespace = runtimeNamespace.ContainingNamespace; | ||
if (systemNamespace?.Name != "System") | ||
{ | ||
return false; | ||
} | ||
|
||
var globalNamespace = systemNamespace.ContainingNamespace; | ||
|
||
return globalNamespace != null && globalNamespace.IsGlobalNamespace; | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
} |
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.
It feels like we might be losing an optimization for this case. #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.
Took a look. We won't be loosing an optimization.
CSDiagnosticInfo.IsEmpty
will returnfalse
fornull
results. Therefore, it won't be initialized. I believe the changed code is simpler to read now.In reply to: 119753756 [](ancestors = 119753756)