未验证 提交 b001cfaa 编写于 作者: A Andy Gocke 提交者: GitHub

Extract SourcePropertySymbolBase class (#45411)

Records need to provide a new form of source property symbol with
different syntax. This PR extracts a new base class to try to share as
much code as possible with the existing SourcePropertySymbol and the
SynthesizedRecordPropertySymbol.
上级 7a836c8e
...@@ -383,17 +383,17 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeSymbol(E ...@@ -383,17 +383,17 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeSymbol(E
#nullable enable #nullable enable
/// <summary> /// <summary>
/// Bind the syntax into a namespace, type or alias symbol. /// Bind the syntax into a namespace, type or alias symbol.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This method is used in deeply recursive parts of the compiler. Specifically this and /// This method is used in deeply recursive parts of the compiler. Specifically this and
/// <see cref="BindQualifiedName(ExpressionSyntax, SimpleNameSyntax, DiagnosticBag, ConsList{TypeSymbol}, bool)"/> /// <see cref="BindQualifiedName(ExpressionSyntax, SimpleNameSyntax, DiagnosticBag, ConsList{TypeSymbol}, bool)"/>
/// are mutually recursive. The non-recursive parts of this method tend to reserve significantly large /// are mutually recursive. The non-recursive parts of this method tend to reserve significantly large
/// stack frames due to their use of large struct like <see cref="TypeWithAnnotations"/>. /// stack frames due to their use of large struct like <see cref="TypeWithAnnotations"/>.
/// ///
/// To keep the stack frame size on recursive paths small the non-recursive parts are factored into local /// To keep the stack frame size on recursive paths small the non-recursive parts are factored into local
/// functions. This means we pay their stack penalty only when they are used. They are themselves big /// functions. This means we pay their stack penalty only when they are used. They are themselves big
/// enough they should be disqualified from inlining. In the future when attributes are allowed on /// enough they should be disqualified from inlining. In the future when attributes are allowed on
/// local functions we should explicitly mark them as <see cref="MethodImplOptions.NoInlining"/> /// local functions we should explicitly mark them as <see cref="MethodImplOptions.NoInlining"/>
/// </remarks> /// </remarks>
internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasSymbol(ExpressionSyntax syntax, DiagnosticBag diagnostics, ConsList<TypeSymbol> basesBeingResolved, bool suppressUseSiteDiagnostics) internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasSymbol(ExpressionSyntax syntax, DiagnosticBag diagnostics, ConsList<TypeSymbol> basesBeingResolved, bool suppressUseSiteDiagnostics)
...@@ -757,7 +757,7 @@ private NamedTypeSymbol BindPredefinedTypeSymbol(PredefinedTypeSyntax node, Diag ...@@ -757,7 +757,7 @@ private NamedTypeSymbol BindPredefinedTypeSymbol(PredefinedTypeSyntax node, Diag
} }
/// <summary> /// <summary>
/// Binds a simple name or the simple name portion of a qualified name. /// Binds a simple name or the simple name portion of a qualified name.
/// </summary> /// </summary>
private NamespaceOrTypeOrAliasSymbolWithAnnotations BindSimpleNamespaceOrTypeOrAliasSymbol( private NamespaceOrTypeOrAliasSymbolWithAnnotations BindSimpleNamespaceOrTypeOrAliasSymbol(
SimpleNameSyntax syntax, SimpleNameSyntax syntax,
...@@ -766,10 +766,10 @@ private NamedTypeSymbol BindPredefinedTypeSymbol(PredefinedTypeSyntax node, Diag ...@@ -766,10 +766,10 @@ private NamedTypeSymbol BindPredefinedTypeSymbol(PredefinedTypeSyntax node, Diag
bool suppressUseSiteDiagnostics, bool suppressUseSiteDiagnostics,
NamespaceOrTypeSymbol qualifierOpt = null) NamespaceOrTypeSymbol qualifierOpt = null)
{ {
// Note that the comment above is a small lie; there is no such thing as the "simple name portion" of // Note that the comment above is a small lie; there is no such thing as the "simple name portion" of
// a qualified alias member expression. A qualified alias member expression has the form // a qualified alias member expression. A qualified alias member expression has the form
// "identifier :: identifier optional-type-arguments" -- the right hand side of which // "identifier :: identifier optional-type-arguments" -- the right hand side of which
// happens to match the syntactic form of a simple name. As a convenience, we analyze the // happens to match the syntactic form of a simple name. As a convenience, we analyze the
// right hand side of the "::" here because it is so similar to a simple name; the left hand // right hand side of the "::" here because it is so similar to a simple name; the left hand
// side is in qualifierOpt. // side is in qualifierOpt.
...@@ -819,7 +819,7 @@ private static bool IsViableType(LookupResult result) ...@@ -819,7 +819,7 @@ private static bool IsViableType(LookupResult result)
var identifierValueText = node.Identifier.ValueText; var identifierValueText = node.Identifier.ValueText;
// If we are here in an error-recovery scenario, say, "goo<int, >(123);" then // If we are here in an error-recovery scenario, say, "goo<int, >(123);" then
// we might have an 'empty' simple name. In that case do not report an // we might have an 'empty' simple name. In that case do not report an
// 'unable to find ""' error; we've already reported an error in the parser so // 'unable to find ""' error; we've already reported an error in the parser so
// just bail out with an error symbol. // just bail out with an error symbol.
...@@ -945,9 +945,9 @@ private static LookupOptions GetSimpleNameLookupOptions(NameSyntax node, bool is ...@@ -945,9 +945,9 @@ private static LookupOptions GetSimpleNameLookupOptions(NameSyntax node, bool is
{ {
if (SyntaxFacts.IsAttributeName(node)) if (SyntaxFacts.IsAttributeName(node))
{ {
// SPEC: By convention, attribute classes are named with a suffix of Attribute. // SPEC: By convention, attribute classes are named with a suffix of Attribute.
// SPEC: An attribute-name of the form type-name may either include or omit this suffix. // SPEC: An attribute-name of the form type-name may either include or omit this suffix.
// SPEC: If an attribute class is found both with and without this suffix, an ambiguity // SPEC: If an attribute class is found both with and without this suffix, an ambiguity
// SPEC: is present, and a compile-time error results. If the attribute-name is spelled // SPEC: is present, and a compile-time error results. If the attribute-name is spelled
// SPEC: such that its right-most identifier is a verbatim identifier (§2.4.2), then only // SPEC: such that its right-most identifier is a verbatim identifier (§2.4.2), then only
// SPEC: an attribute without a suffix is matched, thus enabling such an ambiguity to be resolved. // SPEC: an attribute without a suffix is matched, thus enabling such an ambiguity to be resolved.
...@@ -1036,10 +1036,10 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d ...@@ -1036,10 +1036,10 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d
// us an identifier followed by a type argument list. Therefore they // us an identifier followed by a type argument list. Therefore they
// must expect the result to be a generic type, and not a namespace or alias. // must expect the result to be a generic type, and not a namespace or alias.
// The result of this method will therefore always be a type symbol of the // The result of this method will therefore always be a type symbol of the
// correct arity, though it might have to be an error type. // correct arity, though it might have to be an error type.
// We might be asked to bind a generic simple name of the form "T<,,,>", // We might be asked to bind a generic simple name of the form "T<,,,>",
// which is only legal in the context of "typeof(T<,,,>)". If we are given // which is only legal in the context of "typeof(T<,,,>)". If we are given
// no type arguments and we are not in such a context, we'll give an error. // no type arguments and we are not in such a context, we'll give an error.
...@@ -1051,15 +1051,15 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d ...@@ -1051,15 +1051,15 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d
// * Lookup could fail to find anything at all. // * Lookup could fail to find anything at all.
// * Lookup could find a type of the wrong arity // * Lookup could find a type of the wrong arity
// * Lookup could find something but it is not a type. // * Lookup could find something but it is not a type.
// //
// Second, we could be asked to resolve an unbound type T<,,,> when // Second, we could be asked to resolve an unbound type T<,,,> when
// not in a context where it is legal to do so. Note that this is // not in a context where it is legal to do so. Note that this is
// intended an improvement over the analysis performed by the // intended an improvement over the analysis performed by the
// native compiler; in the native compiler we catch bad uses of unbound // native compiler; in the native compiler we catch bad uses of unbound
// types at parse time, not at semantic analysis time. That means that // types at parse time, not at semantic analysis time. That means that
// we end up giving confusing "unexpected comma" or "expected type" // we end up giving confusing "unexpected comma" or "expected type"
// errors when it would be more informative to the user to simply // errors when it would be more informative to the user to simply
// tell them that an unbound type is not legal in this position. // tell them that an unbound type is not legal in this position.
// //
// This also means that we can get semantic analysis of the open // This also means that we can get semantic analysis of the open
// type in the IDE even in what would have been a syntax error case // type in the IDE even in what would have been a syntax error case
...@@ -1072,11 +1072,11 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d ...@@ -1072,11 +1072,11 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d
// a partially unbound type. // a partially unbound type.
// //
// The heuristic we will use is that the former kind of error takes priority // The heuristic we will use is that the former kind of error takes priority
// over the latter; if the meaning of "Bogus<>" cannot be successfully // over the latter; if the meaning of "Bogus<>" cannot be successfully
// determined then there is no point telling the user that in addition, // determined then there is no point telling the user that in addition,
// it is syntactically wrong. Moreover, at this point we do not know what they // it is syntactically wrong. Moreover, at this point we do not know what they
// mean by the remainder ".Blah<int>" of the expression and so it seems wrong to // mean by the remainder ".Blah<int>" of the expression and so it seems wrong to
// deduce more errors from it. // deduce more errors from it.
var plainName = node.Identifier.ValueText; var plainName = node.Identifier.ValueText;
...@@ -1114,9 +1114,9 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d ...@@ -1114,9 +1114,9 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d
} }
else else
{ {
// It's not an unbound type expression, so we must have type arguments, and we have a // It's not an unbound type expression, so we must have type arguments, and we have a
// generic type of the correct arity in hand (possibly an error type). Bind the type // generic type of the correct arity in hand (possibly an error type). Bind the type
// arguments and construct the final result. // arguments and construct the final result.
resultType = ConstructNamedType( resultType = ConstructNamedType(
unconstructedType, unconstructedType,
node, node,
...@@ -1172,12 +1172,12 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d ...@@ -1172,12 +1172,12 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d
// In the third case we will be given back the symbol -- say, a local variable symbol. // In the third case we will be given back the symbol -- say, a local variable symbol.
// //
// In all three cases the appropriate error has already been reported. (That the // In all three cases the appropriate error has already been reported. (That the
// type was not found, that the generic type found does not have that arity, that // type was not found, that the generic type found does not have that arity, that
// the non-generic type found cannot be used with a type argument list, or that // the non-generic type found cannot be used with a type argument list, or that
// the symbol found is not something that takes type arguments. ) // the symbol found is not something that takes type arguments. )
// The first thing to do is to make sure that we have some sort of generic type in hand. // The first thing to do is to make sure that we have some sort of generic type in hand.
// (Note that an error type symbol is always a generic type.) // (Note that an error type symbol is always a generic type.)
NamedTypeSymbol type = lookupResultSymbol as NamedTypeSymbol; NamedTypeSymbol type = lookupResultSymbol as NamedTypeSymbol;
...@@ -1489,7 +1489,16 @@ internal static bool ReportUseSiteDiagnostics(Symbol symbol, DiagnosticBag diagn ...@@ -1489,7 +1489,16 @@ internal static bool ReportUseSiteDiagnostics(Symbol symbol, DiagnosticBag diagn
/// </summary> /// </summary>
internal NamedTypeSymbol GetWellKnownType(WellKnownType type, DiagnosticBag diagnostics, SyntaxNode node) internal NamedTypeSymbol GetWellKnownType(WellKnownType type, DiagnosticBag diagnostics, SyntaxNode node)
{ {
return GetWellKnownType(this.Compilation, type, diagnostics, node.Location); return GetWellKnownType(type, diagnostics, node.Location);
}
/// <summary>
/// This is a layer on top of the Compilation version that generates a diagnostic if the well-known
/// type isn't found.
/// </summary>
internal NamedTypeSymbol GetWellKnownType(WellKnownType type, DiagnosticBag diagnostics, Location location)
{
return GetWellKnownType(this.Compilation, type, diagnostics, location);
} }
/// <summary> /// <summary>
...@@ -1892,7 +1901,7 @@ public int Compare(Symbol fst, Symbol snd) ...@@ -1892,7 +1901,7 @@ public int Compare(Symbol fst, Symbol snd)
Compilation.IsAttributeType((NamedTypeSymbol)first) && Compilation.IsAttributeType((NamedTypeSymbol)first) &&
Compilation.IsAttributeType((NamedTypeSymbol)second)) Compilation.IsAttributeType((NamedTypeSymbol)second))
{ {
// SPEC: If an attribute class is found both with and without Attribute suffix, an ambiguity // SPEC: If an attribute class is found both with and without Attribute suffix, an ambiguity
// SPEC: is present, and a compile-time error results. // SPEC: is present, and a compile-time error results.
info = new CSDiagnosticInfo(ErrorCode.ERR_AmbiguousAttribute, originalSymbols, info = new CSDiagnosticInfo(ErrorCode.ERR_AmbiguousAttribute, originalSymbols,
...@@ -1960,7 +1969,7 @@ public int Compare(Symbol fst, Symbol snd) ...@@ -1960,7 +1969,7 @@ public int Compare(Symbol fst, Symbol snd)
} }
else if (singleResult.Kind == SymbolKind.ErrorType) else if (singleResult.Kind == SymbolKind.ErrorType)
{ {
// We want to report ERR_CircularBase error on the spot to make sure // We want to report ERR_CircularBase error on the spot to make sure
// that the right location is used for it. // that the right location is used for it.
var errorType = (ErrorTypeSymbol)singleResult; var errorType = (ErrorTypeSymbol)singleResult;
...@@ -2341,7 +2350,7 @@ protected AssemblySymbol GetForwardedToAssembly(string fullName, DiagnosticBag d ...@@ -2341,7 +2350,7 @@ protected AssemblySymbol GetForwardedToAssembly(string fullName, DiagnosticBag d
/// <param name="name">The name of the (potentially) forwarded type.</param> /// <param name="name">The name of the (potentially) forwarded type.</param>
/// <param name="arity">The arity of the forwarded type.</param> /// <param name="arity">The arity of the forwarded type.</param>
/// <param name="qualifierOpt">The namespace of the potentially forwarded type. If none is provided, will /// <param name="qualifierOpt">The namespace of the potentially forwarded type. If none is provided, will
/// try Usings of the current import for eligible namespaces and return the namespace of the found forwarder, /// try Usings of the current import for eligible namespaces and return the namespace of the found forwarder,
/// if any.</param> /// if any.</param>
/// <param name="diagnostics">Will be used to report non-fatal errors during look up.</param> /// <param name="diagnostics">Will be used to report non-fatal errors during look up.</param>
/// <param name="location">Location to report errors on.</param> /// <param name="location">Location to report errors on.</param>
...@@ -2355,8 +2364,8 @@ protected AssemblySymbol GetForwardedToAssembly(string name, int arity, ref Name ...@@ -2355,8 +2364,8 @@ protected AssemblySymbol GetForwardedToAssembly(string name, int arity, ref Name
// If we are in the process of binding assembly level attributes, we might get into an infinite cycle // If we are in the process of binding assembly level attributes, we might get into an infinite cycle
// if any of the referenced assemblies forwards type to this assembly. Since forwarded types // if any of the referenced assemblies forwards type to this assembly. Since forwarded types
// are specified through assembly level attributes, an attempt to resolve the forwarded type // are specified through assembly level attributes, an attempt to resolve the forwarded type
// might require us to examine types forwarded by this assembly, thus binding assembly level // might require us to examine types forwarded by this assembly, thus binding assembly level
// attributes again. And the cycle continues. // attributes again. And the cycle continues.
// So, we won't do the analysis in this case, at the expense of better diagnostics. // So, we won't do the analysis in this case, at the expense of better diagnostics.
if ((this.Flags & BinderFlags.InContextualAttributeBinder) != 0) if ((this.Flags & BinderFlags.InContextualAttributeBinder) != 0)
{ {
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
namespace Microsoft.CodeAnalysis.CSharp namespace Microsoft.CodeAnalysis.CSharp
{ {
/// <summary> /// <summary>
/// Contains methods related to synthesizing bound nodes in initial binding /// Contains methods related to synthesizing bound nodes in initial binding
/// form that needs lowering, primarily method bodies for compiler-generated methods. /// form that needs lowering, primarily method bodies for compiler-generated methods.
/// </summary> /// </summary>
internal static class MethodBodySynthesizer internal static class MethodBodySynthesizer
...@@ -25,8 +25,8 @@ internal static class MethodBodySynthesizer ...@@ -25,8 +25,8 @@ internal static class MethodBodySynthesizer
{ {
// Script field initializers have to be emitted after the call to the base constructor because they can refer to "this" instance. // Script field initializers have to be emitted after the call to the base constructor because they can refer to "this" instance.
// //
// Unlike regular field initializers, initializers of global script variables can access "this" instance. // Unlike regular field initializers, initializers of global script variables can access "this" instance.
// If the base class had a constructor that initializes its state a global variable would access partially initialized object. // If the base class had a constructor that initializes its state a global variable would access partially initialized object.
// For this reason Script class must always derive directly from a class that has no state (System.Object). // For this reason Script class must always derive directly from a class that has no state (System.Object).
SyntaxNode syntax = loweredBody.Syntax; SyntaxNode syntax = loweredBody.Syntax;
...@@ -172,7 +172,7 @@ internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMemberMethodS ...@@ -172,7 +172,7 @@ internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMemberMethodS
{ {
Debug.Assert(accessor.MethodKind == MethodKind.PropertyGet || accessor.MethodKind == MethodKind.PropertySet); Debug.Assert(accessor.MethodKind == MethodKind.PropertyGet || accessor.MethodKind == MethodKind.PropertySet);
var property = (SourcePropertySymbol)accessor.AssociatedSymbol; var property = (SourcePropertySymbolBase)accessor.AssociatedSymbol;
CSharpSyntaxNode syntax = property.CSharpSyntaxNode; CSharpSyntaxNode syntax = property.CSharpSyntaxNode;
BoundExpression thisReference = null; BoundExpression thisReference = null;
if (!accessor.IsStatic) if (!accessor.IsStatic)
...@@ -219,10 +219,10 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody(SourceEventSymbol ...@@ -219,10 +219,10 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody(SourceEventSymbol
/// <summary> /// <summary>
/// Generate a thread-safe accessor for a WinRT field-like event. /// Generate a thread-safe accessor for a WinRT field-like event.
/// ///
/// Add: /// Add:
/// return EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value); /// return EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value);
/// ///
/// Remove: /// Remove:
/// EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value); /// EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value);
/// </summary> /// </summary>
...@@ -302,7 +302,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent ...@@ -302,7 +302,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent
{ {
// { // {
// return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value); // return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value);
// } // }
BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, RefKind.None, processHandlerCall); BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, RefKind.None, processHandlerCall);
return BoundBlock.SynthesizedNoLocals(syntax, returnStatement); return BoundBlock.SynthesizedNoLocals(syntax, returnStatement);
} }
...@@ -311,7 +311,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent ...@@ -311,7 +311,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent
// { // {
// EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value); // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value);
// return; // return;
// } // }
BoundStatement callStatement = new BoundExpressionStatement(syntax, processHandlerCall); BoundStatement callStatement = new BoundExpressionStatement(syntax, processHandlerCall);
BoundStatement returnStatement = new BoundReturnStatement(syntax, RefKind.None, expressionOpt: null); BoundStatement returnStatement = new BoundReturnStatement(syntax, RefKind.None, expressionOpt: null);
return BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement); return BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement);
...@@ -320,7 +320,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent ...@@ -320,7 +320,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent
/// <summary> /// <summary>
/// Generate a thread-safe accessor for a regular field-like event. /// Generate a thread-safe accessor for a regular field-like event.
/// ///
/// DelegateType tmp0 = _event; //backing field /// DelegateType tmp0 = _event; //backing field
/// DelegateType tmp1; /// DelegateType tmp1;
/// DelegateType tmp2; /// DelegateType tmp2;
...@@ -329,12 +329,12 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent ...@@ -329,12 +329,12 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent
/// tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -= /// tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -=
/// tmp0 = Interlocked.CompareExchange&lt;DelegateType&gt;(ref _event, tmp2, tmp1); /// tmp0 = Interlocked.CompareExchange&lt;DelegateType&gt;(ref _event, tmp2, tmp1);
/// } while ((object)tmp0 != (object)tmp1); /// } while ((object)tmp0 != (object)tmp1);
/// ///
/// Note, if System.Threading.Interlocked.CompareExchange&lt;T&gt; is not available, /// Note, if System.Threading.Interlocked.CompareExchange&lt;T&gt; is not available,
/// we emit the following code and mark the method Synchronized (unless it is a struct). /// we emit the following code and mark the method Synchronized (unless it is a struct).
/// ///
/// _event = (DelegateType)Delegate.Combine(_event, value); //Remove for -= /// _event = (DelegateType)Delegate.Combine(_event, value); //Remove for -=
/// ///
/// </summary> /// </summary>
internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics) internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
{ {
...@@ -522,7 +522,7 @@ internal static BoundBlock ConstructDestructorBody(MethodSymbol method, BoundBlo ...@@ -522,7 +522,7 @@ internal static BoundBlock ConstructDestructorBody(MethodSymbol method, BoundBlo
Debug.Assert(method.MethodKind == MethodKind.Destructor); Debug.Assert(method.MethodKind == MethodKind.Destructor);
Debug.Assert(syntax.Kind() == SyntaxKind.Block || syntax.Kind() == SyntaxKind.ArrowExpressionClause); Debug.Assert(syntax.Kind() == SyntaxKind.Block || syntax.Kind() == SyntaxKind.ArrowExpressionClause);
// If this is a destructor and a base type has a Finalize method (see GetBaseTypeFinalizeMethod for exact // If this is a destructor and a base type has a Finalize method (see GetBaseTypeFinalizeMethod for exact
// requirements), then we need to call that method in a finally block. Otherwise, just return block as-is. // requirements), then we need to call that method in a finally block. Otherwise, just return block as-is.
// NOTE: the Finalize method need not be a destructor or be overridden by the current method. // NOTE: the Finalize method need not be a destructor or be overridden by the current method.
MethodSymbol baseTypeFinalize = GetBaseTypeFinalizeMethod(method); MethodSymbol baseTypeFinalize = GetBaseTypeFinalizeMethod(method);
...@@ -572,11 +572,11 @@ internal static BoundBlock ConstructDestructorBody(MethodSymbol method, BoundBlo ...@@ -572,11 +572,11 @@ internal static BoundBlock ConstructDestructorBody(MethodSymbol method, BoundBlo
} }
/// <summary> /// <summary>
/// Look for a base type method named "Finalize" that is protected (or protected internal), has no parameters, /// Look for a base type method named "Finalize" that is protected (or protected internal), has no parameters,
/// and returns void. It doesn't need to be virtual or a destructor. /// and returns void. It doesn't need to be virtual or a destructor.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// You may assume that this would share code and logic with PEMethodSymbol.OverridesRuntimeFinalizer, /// You may assume that this would share code and logic with PEMethodSymbol.OverridesRuntimeFinalizer,
/// but FUNCBRECCS::bindDestructor has its own loop that performs these checks (differently). /// but FUNCBRECCS::bindDestructor has its own loop that performs these checks (differently).
/// </remarks> /// </remarks>
private static MethodSymbol GetBaseTypeFinalizeMethod(MethodSymbol method) private static MethodSymbol GetBaseTypeFinalizeMethod(MethodSymbol method)
......
...@@ -39,16 +39,16 @@ internal sealed class MethodCompiler : CSharpSymbolVisitor<TypeCompilationState, ...@@ -39,16 +39,16 @@ internal sealed class MethodCompiler : CSharpSymbolVisitor<TypeCompilationState,
// MethodCompiler employs concurrency by following flattened fork/join pattern. // MethodCompiler employs concurrency by following flattened fork/join pattern.
// //
// For every item that we want to compile in parallel a new task is forked. // For every item that we want to compile in parallel a new task is forked.
// compileTaskQueue is used to track and observe all the tasks. // compileTaskQueue is used to track and observe all the tasks.
// Once compileTaskQueue is empty, we know that there are no more tasks (and no more can be created) // Once compileTaskQueue is empty, we know that there are no more tasks (and no more can be created)
// and that means we are done compiling. WaitForWorkers ensures this condition. // and that means we are done compiling. WaitForWorkers ensures this condition.
// //
// Note that while tasks may fork more tasks (nested types, lambdas, whatever else that may introduce more types), // Note that while tasks may fork more tasks (nested types, lambdas, whatever else that may introduce more types),
// we do not want any child/parent relationship between spawned tasks and their creators. // we do not want any child/parent relationship between spawned tasks and their creators.
// Creator has no real dependencies on the completion of its children and should finish and release any resources // Creator has no real dependencies on the completion of its children and should finish and release any resources
// as soon as it can regardless of the tasks it may have spawned. // as soon as it can regardless of the tasks it may have spawned.
// //
// Stack is used so that the wait would observe the most recently added task and have // Stack is used so that the wait would observe the most recently added task and have
// more chances to do inlined execution. // more chances to do inlined execution.
private ConcurrentStack<Task> _compilerTasks; private ConcurrentStack<Task> _compilerTasks;
...@@ -70,7 +70,7 @@ private void SetGlobalErrorIfTrue(bool arg) ...@@ -70,7 +70,7 @@ private void SetGlobalErrorIfTrue(bool arg)
// It is ok if other tasks will see the change after some delay or does not observe at all. // It is ok if other tasks will see the change after some delay or does not observe at all.
// Such races are unavoidable and will just result in performing some work that is safe to do // Such races are unavoidable and will just result in performing some work that is safe to do
// but may no longer be needed. // but may no longer be needed.
// The final Join of compiling tasks cannot happen without interlocked operations and that // The final Join of compiling tasks cannot happen without interlocked operations and that
// will ensure that any write of the flag is globally visible. // will ensure that any write of the flag is globally visible.
if (arg) if (arg)
{ {
...@@ -119,7 +119,7 @@ private void SetGlobalErrorIfTrue(bool arg) ...@@ -119,7 +119,7 @@ private void SetGlobalErrorIfTrue(bool arg)
if (compilation.PreviousSubmission != null) if (compilation.PreviousSubmission != null)
{ {
// In case there is a previous submission, we should ensure // In case there is a previous submission, we should ensure
// it has already created anonymous type/delegates templates // it has already created anonymous type/delegates templates
// NOTE: if there are any errors, we will pick up what was created anyway // NOTE: if there are any errors, we will pick up what was created anyway
...@@ -515,7 +515,7 @@ private void CompileNamedType(NamedTypeSymbol containingType) ...@@ -515,7 +515,7 @@ private void CompileNamedType(NamedTypeSymbol containingType)
case SymbolKind.Property: case SymbolKind.Property:
{ {
SourcePropertySymbol sourceProperty = member as SourcePropertySymbol; var sourceProperty = member as SourcePropertySymbolBase;
if ((object)sourceProperty != null && sourceProperty.IsSealed && compilationState.Emitting) if ((object)sourceProperty != null && sourceProperty.IsSealed && compilationState.Emitting)
{ {
CompileSynthesizedSealedAccessors(sourceProperty, compilationState); CompileSynthesizedSealedAccessors(sourceProperty, compilationState);
...@@ -690,7 +690,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) ...@@ -690,7 +690,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
var importChain = methodWithBody.ImportChain; var importChain = methodWithBody.ImportChain;
compilationState.CurrentImportChain = importChain; compilationState.CurrentImportChain = importChain;
// We make sure that an asynchronous mutation to the diagnostic bag does not // We make sure that an asynchronous mutation to the diagnostic bag does not
// confuse the method body generator by making a fresh bag and then loading // confuse the method body generator by making a fresh bag and then loading
// any diagnostics emitted into it back into the main diagnostic bag. // any diagnostics emitted into it back into the main diagnostic bag.
var diagnosticsThisMethod = DiagnosticBag.GetInstance(); var diagnosticsThisMethod = DiagnosticBag.GetInstance();
...@@ -702,7 +702,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) ...@@ -702,7 +702,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
_moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(method, method, diagnosticsThisMethod); _moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(method, method, diagnosticsThisMethod);
// Synthesized methods have no ordinal stored in custom debug information (only user-defined methods have ordinals). // Synthesized methods have no ordinal stored in custom debug information (only user-defined methods have ordinals).
// In case of async lambdas, which synthesize a state machine type during the following rewrite, the containing method has already been uniquely named, // In case of async lambdas, which synthesize a state machine type during the following rewrite, the containing method has already been uniquely named,
// so there is no need to produce a unique method ordinal for the corresponding state machine type, whose name includes the (unique) containing method name. // so there is no need to produce a unique method ordinal for the corresponding state machine type, whose name includes the (unique) containing method name.
const int methodOrdinal = -1; const int methodOrdinal = -1;
MethodBody emittedBody = null; MethodBody emittedBody = null;
...@@ -775,7 +775,7 @@ private static bool IsFieldLikeEventAccessor(MethodSymbol method) ...@@ -775,7 +775,7 @@ private static bool IsFieldLikeEventAccessor(MethodSymbol method)
} }
/// <summary> /// <summary>
/// In some circumstances (e.g. implicit implementation of an interface method by a non-virtual method in a /// In some circumstances (e.g. implicit implementation of an interface method by a non-virtual method in a
/// base type from another assembly) it is necessary for the compiler to generate explicit implementations for /// base type from another assembly) it is necessary for the compiler to generate explicit implementations for
/// some interface methods. They don't go in the symbol table, but if we are emitting, then we should /// some interface methods. They don't go in the symbol table, but if we are emitting, then we should
/// generate code for them. /// generate code for them.
...@@ -797,7 +797,7 @@ private void CompileSynthesizedExplicitImplementations(SourceMemberContainerType ...@@ -797,7 +797,7 @@ private void CompileSynthesizedExplicitImplementations(SourceMemberContainerType
} }
} }
private void CompileSynthesizedSealedAccessors(SourcePropertySymbol sourceProperty, TypeCompilationState compilationState) private void CompileSynthesizedSealedAccessors(SourcePropertySymbolBase sourceProperty, TypeCompilationState compilationState)
{ {
SynthesizedSealedPropertyAccessor synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt; SynthesizedSealedPropertyAccessor synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt;
...@@ -991,9 +991,9 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum ...@@ -991,9 +991,9 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
UnassignedFieldsWalker.Analyze(_compilation, methodSymbol, body, diagsForCurrentMethod); UnassignedFieldsWalker.Analyze(_compilation, methodSymbol, body, diagsForCurrentMethod);
} }
// lower initializers just once. the lowered tree will be reused when emitting all constructors // lower initializers just once. the lowered tree will be reused when emitting all constructors
// with field initializers. Once lowered, these initializers will be stashed in processedInitializers.LoweredInitializers // with field initializers. Once lowered, these initializers will be stashed in processedInitializers.LoweredInitializers
// (see later in this method). Don't bother lowering _now_ if this particular ctor won't have the initializers // (see later in this method). Don't bother lowering _now_ if this particular ctor won't have the initializers
// appended to its body. // appended to its body.
if (includeInitializersInBody && processedInitializers.LoweredInitializers == null) if (includeInitializersInBody && processedInitializers.LoweredInitializers == null)
{ {
...@@ -1098,7 +1098,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum ...@@ -1098,7 +1098,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
_compilation.EventQueue.TryEnqueue(new SymbolDeclaredCompilationEvent(_compilation, methodSymbol.GetPublicSymbol(), lazySemanticModel)); _compilation.EventQueue.TryEnqueue(new SymbolDeclaredCompilationEvent(_compilation, methodSymbol.GetPublicSymbol(), lazySemanticModel));
} }
// Don't lower if we're not emitting or if there were errors. // Don't lower if we're not emitting or if there were errors.
// Methods that had binding errors are considered too broken to be lowered reliably. // Methods that had binding errors are considered too broken to be lowered reliably.
if (_moduleBeingBuiltOpt == null || hasErrors) if (_moduleBeingBuiltOpt == null || hasErrors)
{ {
...@@ -1108,7 +1108,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum ...@@ -1108,7 +1108,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
// ############################ // ############################
// LOWERING AND EMIT // LOWERING AND EMIT
// Any errors generated below here are considered Emit diagnostics // Any errors generated below here are considered Emit diagnostics
// and will not be reported to callers Compilation.GetDiagnostics() // and will not be reported to callers Compilation.GetDiagnostics()
ImmutableArray<SourceSpan> dynamicAnalysisSpans = ImmutableArray<SourceSpan>.Empty; ImmutableArray<SourceSpan> dynamicAnalysisSpans = ImmutableArray<SourceSpan>.Empty;
...@@ -1320,9 +1320,9 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum ...@@ -1320,9 +1320,9 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
if (sawAwaitInExceptionHandler) if (sawAwaitInExceptionHandler)
{ {
// If we have awaits in handlers, we need to // If we have awaits in handlers, we need to
// replace handlers with synthetic ones which can be consumed by async rewriter. // replace handlers with synthetic ones which can be consumed by async rewriter.
// The reason why this rewrite happens before the lambda rewrite // The reason why this rewrite happens before the lambda rewrite
// is that we may need access to exception locals and it would be fairly hard to do // is that we may need access to exception locals and it would be fairly hard to do
// if these locals are captured into closures (possibly nested ones). // if these locals are captured into closures (possibly nested ones).
loweredBody = AsyncExceptionHandlerRewriter.Rewrite( loweredBody = AsyncExceptionHandlerRewriter.Rewrite(
...@@ -1442,7 +1442,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum ...@@ -1442,7 +1442,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
isAsyncStateMachine = kickoffMethod.IsAsync; isAsyncStateMachine = kickoffMethod.IsAsync;
// Async void method may be partial. Debug info needs to be associated with the emitted definition, // Async void method may be partial. Debug info needs to be associated with the emitted definition,
// but the kickoff method is the method implementation (the part with body). // but the kickoff method is the method implementation (the part with body).
kickoffMethod = kickoffMethod.PartialDefinitionPart ?? kickoffMethod; kickoffMethod = kickoffMethod.PartialDefinitionPart ?? kickoffMethod;
} }
...@@ -1488,7 +1488,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum ...@@ -1488,7 +1488,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
var stateMachineHoistedLocalScopes = ((object)kickoffMethod != null) ? var stateMachineHoistedLocalScopes = ((object)kickoffMethod != null) ?
builder.GetHoistedLocalScopes() : default(ImmutableArray<StateMachineHoistedLocalScope>); builder.GetHoistedLocalScopes() : default(ImmutableArray<StateMachineHoistedLocalScope>);
// Translate the imports even if we are not writing PDBs. The translation has an impact on generated metadata // Translate the imports even if we are not writing PDBs. The translation has an impact on generated metadata
// and we don't want to emit different metadata depending on whether or we emit with PDB stream. // and we don't want to emit different metadata depending on whether or we emit with PDB stream.
// TODO (https://github.com/dotnet/roslyn/issues/2846): This will need to change for member initializers in partial class. // TODO (https://github.com/dotnet/roslyn/issues/2846): This will need to change for member initializers in partial class.
var importScopeOpt = importChainOpt?.Translate(moduleBuilder, diagnosticsForThisMethod); var importScopeOpt = importChainOpt?.Translate(moduleBuilder, diagnosticsForThisMethod);
...@@ -1722,7 +1722,7 @@ internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationSt ...@@ -1722,7 +1722,7 @@ internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationSt
} }
else else
{ {
var property = sourceMethod.AssociatedSymbol as SourcePropertySymbol; var property = sourceMethod.AssociatedSymbol as SourcePropertySymbolBase;
if ((object)property != null && property.IsAutoProperty) if ((object)property != null && property.IsAutoProperty)
{ {
return MethodBodySynthesizer.ConstructAutoPropertyAccessorBody(sourceMethod); return MethodBodySynthesizer.ConstructAutoPropertyAccessorBody(sourceMethod);
...@@ -1863,7 +1863,7 @@ private static void ReportCtorInitializerCycles(MethodSymbol method, BoundExpres ...@@ -1863,7 +1863,7 @@ private static void ReportCtorInitializerCycles(MethodSymbol method, BoundExpres
// to be inside the body of a derived class in order for it to be in the // to be inside the body of a derived class in order for it to be in the
// accessibility domain of the protected base class ctor. // accessibility domain of the protected base class ctor.
// //
// In the second case the binder could be the binder associated with // In the second case the binder could be the binder associated with
// the body of D2; since the implicit call to base() will have no arguments // the body of D2; since the implicit call to base() will have no arguments
// there is no need to look up "x". // there is no need to look up "x".
Binder outerBinder; Binder outerBinder;
...@@ -1871,7 +1871,7 @@ private static void ReportCtorInitializerCycles(MethodSymbol method, BoundExpres ...@@ -1871,7 +1871,7 @@ private static void ReportCtorInitializerCycles(MethodSymbol method, BoundExpres
if ((object)sourceConstructor == null) if ((object)sourceConstructor == null)
{ {
// The constructor is implicit. We need to get the binder for the body // The constructor is implicit. We need to get the binder for the body
// of the enclosing class. // of the enclosing class.
CSharpSyntaxNode containerNode = constructor.GetNonNullSyntaxNode(); CSharpSyntaxNode containerNode = constructor.GetNonNullSyntaxNode();
BinderFactory binderFactory = compilation.GetBinderFactory(containerNode.SyntaxTree); BinderFactory binderFactory = compilation.GetBinderFactory(containerNode.SyntaxTree);
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
namespace Microsoft.CodeAnalysis.CSharp namespace Microsoft.CodeAnalysis.CSharp
{ {
/// <summary> /// <summary>
/// When compiling in metadata-only mode, <see cref="MethodCompiler"/> is not run. This is problematic because /// When compiling in metadata-only mode, <see cref="MethodCompiler"/> is not run. This is problematic because
/// <see cref="MethodCompiler"/> adds synthesized explicit implementations to the list of synthesized definitions. /// <see cref="MethodCompiler"/> adds synthesized explicit implementations to the list of synthesized definitions.
/// In lieu of running <see cref="MethodCompiler"/>, this class performs a quick /// In lieu of running <see cref="MethodCompiler"/>, this class performs a quick
/// traversal of the symbol table and performs processing of synthesized symbols if necessary /// traversal of the symbol table and performs processing of synthesized symbols if necessary
/// </summary> /// </summary>
internal sealed class SynthesizedMetadataCompiler : CSharpSymbolVisitor internal sealed class SynthesizedMetadataCompiler : CSharpSymbolVisitor
...@@ -66,7 +66,7 @@ public override void VisitNamedType(NamedTypeSymbol symbol) ...@@ -66,7 +66,7 @@ public override void VisitNamedType(NamedTypeSymbol symbol)
{ {
if (_moduleBeingBuilt != null) if (_moduleBeingBuilt != null)
{ {
// In some circumstances (e.g. implicit implementation of an interface method by a non-virtual method in a // In some circumstances (e.g. implicit implementation of an interface method by a non-virtual method in a
// base type from another assembly) it is necessary for the compiler to generate explicit implementations for // base type from another assembly) it is necessary for the compiler to generate explicit implementations for
// some interface methods. They don't go in the symbol table, but if we are emitting metadata, then we should // some interface methods. They don't go in the symbol table, but if we are emitting metadata, then we should
// generate MethodDef entries for them. // generate MethodDef entries for them.
...@@ -91,7 +91,7 @@ public override void VisitNamedType(NamedTypeSymbol symbol) ...@@ -91,7 +91,7 @@ public override void VisitNamedType(NamedTypeSymbol symbol)
public override void VisitProperty(PropertySymbol symbol) public override void VisitProperty(PropertySymbol symbol)
{ {
var sourceProperty = symbol as SourcePropertySymbol; var sourceProperty = symbol as SourcePropertySymbolBase;
if ((object)sourceProperty != null && sourceProperty.IsSealed) if ((object)sourceProperty != null && sourceProperty.IsSealed)
{ {
var synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt; var synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt;
......
...@@ -33,7 +33,7 @@ IEnumerable<IMethodReference> IPropertyDefinition.GetAccessors(EmitContext conte ...@@ -33,7 +33,7 @@ IEnumerable<IMethodReference> IPropertyDefinition.GetAccessors(EmitContext conte
yield return setMethod; yield return setMethod;
} }
SourcePropertySymbol sourceProperty = this as SourcePropertySymbol; var sourceProperty = this as SourcePropertySymbolBase;
if ((object)sourceProperty != null && sourceProperty.ShouldInclude(context)) if ((object)sourceProperty != null && sourceProperty.ShouldInclude(context))
{ {
SynthesizedSealedPropertyAccessor synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt; SynthesizedSealedPropertyAccessor synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt;
...@@ -266,7 +266,7 @@ string INamedEntity.Name ...@@ -266,7 +266,7 @@ string INamedEntity.Name
private IMethodReference GetSynthesizedSealedAccessor(MethodKind targetMethodKind) private IMethodReference GetSynthesizedSealedAccessor(MethodKind targetMethodKind)
{ {
SourcePropertySymbol sourceProperty = this as SourcePropertySymbol; var sourceProperty = this as SourcePropertySymbolBase;
if ((object)sourceProperty != null) if ((object)sourceProperty != null)
{ {
SynthesizedSealedPropertyAccessor synthesized = sourceProperty.SynthesizedSealedAccessorOpt; SynthesizedSealedPropertyAccessor synthesized = sourceProperty.SynthesizedSealedAccessorOpt;
......
...@@ -563,7 +563,7 @@ protected void VisitLvalue(BoundExpression node) ...@@ -563,7 +563,7 @@ protected void VisitLvalue(BoundExpression node)
if (Binder.AccessingAutoPropertyFromConstructor(access, _symbol)) if (Binder.AccessingAutoPropertyFromConstructor(access, _symbol))
{ {
var backingField = (access.PropertySymbol as SourcePropertySymbol)?.BackingField; var backingField = (access.PropertySymbol as SourcePropertySymbolBase)?.BackingField;
if (backingField != null) if (backingField != null)
{ {
VisitFieldAccessInternal(access.ReceiverOpt, backingField); VisitFieldAccessInternal(access.ReceiverOpt, backingField);
...@@ -1077,7 +1077,7 @@ public override BoundNode VisitStringInsert(BoundStringInsert node) ...@@ -1077,7 +1077,7 @@ public override BoundNode VisitStringInsert(BoundStringInsert node)
public override BoundNode VisitArgList(BoundArgList node) public override BoundNode VisitArgList(BoundArgList node)
{ {
// The "__arglist" expression that is legal inside a varargs method has no // The "__arglist" expression that is legal inside a varargs method has no
// effect on flow analysis and it has no children. // effect on flow analysis and it has no children.
return null; return null;
} }
...@@ -1576,7 +1576,7 @@ public override BoundNode VisitTryStatement(BoundTryStatement node) ...@@ -1576,7 +1576,7 @@ public override BoundNode VisitTryStatement(BoundTryStatement node)
RestorePending(pendingBeforeTry); RestorePending(pendingBeforeTry);
// NOTE: At this point all branches that are internal to try or catch blocks have been resolved. // NOTE: At this point all branches that are internal to try or catch blocks have been resolved.
// However we have not yet restored the oldPending branches. Therefore all the branches // However we have not yet restored the oldPending branches. Therefore all the branches
// that are currently pending must have been introduced in try/catch and do not terminate inside those blocks. // that are currently pending must have been introduced in try/catch and do not terminate inside those blocks.
// //
// With exception of YieldReturn, these branches logically go through finally, if such present, // With exception of YieldReturn, these branches logically go through finally, if such present,
...@@ -1811,7 +1811,7 @@ protected virtual void PropertySetter(BoundExpression node, BoundExpression rece ...@@ -1811,7 +1811,7 @@ protected virtual void PropertySetter(BoundExpression node, BoundExpression rece
VisitReceiverAfterCall(receiver, setter); VisitReceiverAfterCall(receiver, setter);
} }
// returns false if expression is not a property access // returns false if expression is not a property access
// or if the property has a backing field // or if the property has a backing field
// and accessed in a corresponding constructor // and accessed in a corresponding constructor
private bool RegularPropertyAccess(BoundExpression expr) private bool RegularPropertyAccess(BoundExpression expr)
...@@ -1958,7 +1958,7 @@ public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) ...@@ -1958,7 +1958,7 @@ public override BoundNode VisitPropertyAccess(BoundPropertyAccess node)
if (Binder.AccessingAutoPropertyFromConstructor(node, _symbol)) if (Binder.AccessingAutoPropertyFromConstructor(node, _symbol))
{ {
var backingField = (property as SourcePropertySymbol)?.BackingField; var backingField = (property as SourcePropertySymbolBase)?.BackingField;
if (backingField != null) if (backingField != null)
{ {
VisitFieldAccessInternal(node.ReceiverOpt, backingField); VisitFieldAccessInternal(node.ReceiverOpt, backingField);
...@@ -3144,10 +3144,10 @@ private void VisitMethodBodies(BoundBlock blockBody, BoundBlock expressionBody) ...@@ -3144,10 +3144,10 @@ private void VisitMethodBodies(BoundBlock blockBody, BoundBlock expressionBody)
// In error cases we have two bodies. These are two unrelated pieces of code, // In error cases we have two bodies. These are two unrelated pieces of code,
// they are not executed one after another. As we don't really know which one the developer // they are not executed one after another. As we don't really know which one the developer
// intended to use, we need to visit both. We are going to pretend that there is // intended to use, we need to visit both. We are going to pretend that there is
// an unconditional fork in execution and then we are converging after each body is executed. // an unconditional fork in execution and then we are converging after each body is executed.
// For example, if only one body assigns an out parameter, then after visiting both bodies // For example, if only one body assigns an out parameter, then after visiting both bodies
// we should consider that parameter is not definitely assigned. // we should consider that parameter is not definitely assigned.
// Note, that today this code is not executed for regular definite assignment analysis. It is // Note, that today this code is not executed for regular definite assignment analysis. It is
// only executed for region analysis. // only executed for region analysis.
TLocalState initialState = this.State.Clone(); TLocalState initialState = this.State.Clone();
Visit(blockBody); Visit(blockBody);
......
...@@ -584,11 +584,11 @@ protected virtual void NoteWrite(Symbol variable, BoundExpression value, bool re ...@@ -584,11 +584,11 @@ protected virtual void NoteWrite(Symbol variable, BoundExpression value, bool re
// unless the written value is always a constant. The reasons for this // unless the written value is always a constant. The reasons for this
// unusual behavior are: // unusual behavior are:
// //
// * The debugger does not make it easy to see the returned value of // * The debugger does not make it easy to see the returned value of
// a method. Often a call whose returned value would normally be // a method. Often a call whose returned value would normally be
// discarded is written into a local variable so that it can be // discarded is written into a local variable so that it can be
// easily inspected in the debugger. // easily inspected in the debugger.
// //
// * An otherwise unread local variable that contains a reference to an // * An otherwise unread local variable that contains a reference to an
// object can keep the object alive longer, particularly if the jitter // object can keep the object alive longer, particularly if the jitter
// is not optimizing the lifetimes of locals. (Because, for example, // is not optimizing the lifetimes of locals. (Because, for example,
...@@ -597,7 +597,7 @@ protected virtual void NoteWrite(Symbol variable, BoundExpression value, bool re ...@@ -597,7 +597,7 @@ protected virtual void NoteWrite(Symbol variable, BoundExpression value, bool re
// the developer to more easily examine its state. // the developer to more easily examine its state.
// //
// * A developer who wishes to deliberately discard a value returned by // * A developer who wishes to deliberately discard a value returned by
// a method can do so in a self-documenting manner via // a method can do so in a self-documenting manner via
// "var unread = M();" // "var unread = M();"
// //
// We suppress the "written but not read" message on locals unless what is // We suppress the "written but not read" message on locals unless what is
...@@ -625,7 +625,7 @@ internal static bool WriteConsideredUse(TypeSymbol type, BoundExpression value) ...@@ -625,7 +625,7 @@ internal static bool WriteConsideredUse(TypeSymbol type, BoundExpression value)
if ((object)type != null && type.IsPointerOrFunctionPointer()) if ((object)type != null && type.IsPointerOrFunctionPointer())
{ {
// We always suppress the warning for pointer types. // We always suppress the warning for pointer types.
return true; return true;
} }
...@@ -798,7 +798,7 @@ protected override bool TryGetReceiverAndMember(BoundExpression expr, out BoundE ...@@ -798,7 +798,7 @@ protected override bool TryGetReceiverAndMember(BoundExpression expr, out BoundE
if (Binder.AccessingAutoPropertyFromConstructor(propAccess, this.CurrentSymbol)) if (Binder.AccessingAutoPropertyFromConstructor(propAccess, this.CurrentSymbol))
{ {
var propSymbol = propAccess.PropertySymbol; var propSymbol = propAccess.PropertySymbol;
member = (propSymbol as SourcePropertySymbol)?.BackingField; member = (propSymbol as SourcePropertySymbolBase)?.BackingField;
if (member is null) if (member is null)
{ {
return false; return false;
...@@ -1023,7 +1023,7 @@ private bool IsAssigned(BoundExpression node, out int unassignedSlot) ...@@ -1023,7 +1023,7 @@ private bool IsAssigned(BoundExpression node, out int unassignedSlot)
if (Binder.AccessingAutoPropertyFromConstructor(propertyAccess, this.CurrentSymbol)) if (Binder.AccessingAutoPropertyFromConstructor(propertyAccess, this.CurrentSymbol))
{ {
var property = propertyAccess.PropertySymbol; var property = propertyAccess.PropertySymbol;
var backingField = (property as SourcePropertySymbol)?.BackingField; var backingField = (property as SourcePropertySymbolBase)?.BackingField;
if (backingField != null) if (backingField != null)
{ {
if (!MayRequireTracking(propertyAccess.ReceiverOpt, backingField) || IsAssigned(propertyAccess.ReceiverOpt, out unassignedSlot)) if (!MayRequireTracking(propertyAccess.ReceiverOpt, backingField) || IsAssigned(propertyAccess.ReceiverOpt, out unassignedSlot))
...@@ -2036,7 +2036,7 @@ public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) ...@@ -2036,7 +2036,7 @@ public override BoundNode VisitPropertyAccess(BoundPropertyAccess node)
if (Binder.AccessingAutoPropertyFromConstructor(node, this.CurrentSymbol)) if (Binder.AccessingAutoPropertyFromConstructor(node, this.CurrentSymbol))
{ {
var property = node.PropertySymbol; var property = node.PropertySymbol;
var backingField = (property as SourcePropertySymbol)?.BackingField; var backingField = (property as SourcePropertySymbolBase)?.BackingField;
if (backingField != null) if (backingField != null)
{ {
if (MayRequireTracking(node.ReceiverOpt, backingField)) if (MayRequireTracking(node.ReceiverOpt, backingField))
......
...@@ -7039,14 +7039,14 @@ static FlowAnalysisAnnotations getSetterAnnotations(PropertySymbol property) ...@@ -7039,14 +7039,14 @@ static FlowAnalysisAnnotations getSetterAnnotations(PropertySymbol property)
{ {
return accessor.Parameters.Last().FlowAnalysisAnnotations; return accessor.Parameters.Last().FlowAnalysisAnnotations;
} }
if (property is SourcePropertySymbol sourceProperty) if (property is SourcePropertySymbolBase sourceProperty)
{ {
return getPropertyAnnotations(sourceProperty); return getPropertyAnnotations(sourceProperty);
} }
return FlowAnalysisAnnotations.None; return FlowAnalysisAnnotations.None;
} }
static FlowAnalysisAnnotations getPropertyAnnotations(SourcePropertySymbol property) static FlowAnalysisAnnotations getPropertyAnnotations(SourcePropertySymbolBase property)
{ {
var annotations = FlowAnalysisAnnotations.None; var annotations = FlowAnalysisAnnotations.None;
if (property.HasAllowNull) if (property.HasAllowNull)
......
...@@ -300,7 +300,7 @@ private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bo ...@@ -300,7 +300,7 @@ private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bo
if (setMethod is null) if (setMethod is null)
{ {
var autoProp = (SourceOrRecordPropertySymbol)property; var autoProp = (SourcePropertySymbolBase)property;
Debug.Assert(autoProp.IsAutoProperty, Debug.Assert(autoProp.IsAutoProperty,
"only autoproperties can be assignable without having setters"); "only autoproperties can be assignable without having setters");
......
...@@ -104,7 +104,7 @@ private static bool ShouldMethodDisplayReadOnly(IMethodSymbol method, IPropertyS ...@@ -104,7 +104,7 @@ private static bool ShouldMethodDisplayReadOnly(IMethodSymbol method, IPropertyS
} }
if ((method as Symbols.PublicModel.MethodSymbol)?.UnderlyingMethodSymbol is SourcePropertyAccessorSymbol sourceAccessor && if ((method as Symbols.PublicModel.MethodSymbol)?.UnderlyingMethodSymbol is SourcePropertyAccessorSymbol sourceAccessor &&
(propertyOpt as Symbols.PublicModel.PropertySymbol)?.UnderlyingSymbol is SourcePropertySymbol sourceProperty) (propertyOpt as Symbols.PublicModel.PropertySymbol)?.UnderlyingSymbol is SourcePropertySymbolBase sourceProperty)
{ {
// only display if the accessor is explicitly readonly // only display if the accessor is explicitly readonly
return sourceAccessor.LocalDeclaredReadOnly || sourceProperty.HasReadOnlyModifier; return sourceAccessor.LocalDeclaredReadOnly || sourceProperty.HasReadOnlyModifier;
...@@ -319,7 +319,7 @@ public override void VisitMethod(IMethodSymbol symbol) ...@@ -319,7 +319,7 @@ public override void VisitMethod(IMethodSymbol symbol)
} }
} }
// Method members always have a type unless (1) this is a lambda method symbol, which we // Method members always have a type unless (1) this is a lambda method symbol, which we
// have dealt with already, or (2) this is an error method symbol. If we have an error method // have dealt with already, or (2) this is an error method symbol. If we have an error method
// symbol then we do not know its accessibility, modifiers, etc, all of which require knowing // symbol then we do not know its accessibility, modifiers, etc, all of which require knowing
// the containing type, so we'll skip them. // the containing type, so we'll skip them.
...@@ -343,7 +343,7 @@ public override void VisitMethod(IMethodSymbol symbol) ...@@ -343,7 +343,7 @@ public override void VisitMethod(IMethodSymbol symbol)
break; break;
case MethodKind.Destructor: case MethodKind.Destructor:
case MethodKind.Conversion: case MethodKind.Conversion:
// If we're using the metadata format, then include the return type. // If we're using the metadata format, then include the return type.
// Otherwise we eschew it since it is redundant in a conversion // Otherwise we eschew it since it is redundant in a conversion
// signature. // signature.
if (format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames)) if (format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames))
...@@ -354,8 +354,8 @@ public override void VisitMethod(IMethodSymbol symbol) ...@@ -354,8 +354,8 @@ public override void VisitMethod(IMethodSymbol symbol)
break; break;
default: default:
// The display code is called by the debugger; if a developer is debugging Roslyn and attempts // The display code is called by the debugger; if a developer is debugging Roslyn and attempts
// to visualize a symbol *during its construction*, the parameters and return type might // to visualize a symbol *during its construction*, the parameters and return type might
// still be null. // still be null.
if (symbol.ReturnsByRef) if (symbol.ReturnsByRef)
{ {
...@@ -777,8 +777,8 @@ private void AddParametersIfRequired(bool hasThisParameter, bool isVarargs, Immu ...@@ -777,8 +777,8 @@ private void AddParametersIfRequired(bool hasThisParameter, bool isVarargs, Immu
var first = true; var first = true;
// The display code is called by the debugger; if a developer is debugging Roslyn and attempts // The display code is called by the debugger; if a developer is debugging Roslyn and attempts
// to visualize a symbol *during its construction*, the parameters and return type might // to visualize a symbol *during its construction*, the parameters and return type might
// still be null. // still be null.
if (!parameters.IsDefault) if (!parameters.IsDefault)
{ {
......
...@@ -986,7 +986,7 @@ internal bool TryCalculateSyntaxOffsetOfPositionInInitializer(int position, Synt ...@@ -986,7 +986,7 @@ internal bool TryCalculateSyntaxOffsetOfPositionInInitializer(int position, Synt
// |<-----------distanceFromCtorBody----------->| // |<-----------distanceFromCtorBody----------->|
// [ initializer 0 ][ initializer 1 ][ initializer 2 ][ctor initializer][ctor body] // [ initializer 0 ][ initializer 1 ][ initializer 2 ][ctor initializer][ctor body]
// |<--preceding init len-->| ^ // |<--preceding init len-->| ^
// position // position
int initializersLength = isStatic ? membersAndInitializers.StaticInitializersSyntaxLength : membersAndInitializers.InstanceInitializersSyntaxLength; int initializersLength = isStatic ? membersAndInitializers.StaticInitializersSyntaxLength : membersAndInitializers.InstanceInitializersSyntaxLength;
int distanceFromInitializerStart = position - siblingInitializers[index].Syntax.Span.Start; int distanceFromInitializerStart = position - siblingInitializers[index].Syntax.Span.Start;
...@@ -1255,7 +1255,7 @@ internal override IEnumerable<FieldSymbol> GetFieldsToEmit() ...@@ -1255,7 +1255,7 @@ internal override IEnumerable<FieldSymbol> GetFieldsToEmit()
/// <summary> /// <summary>
/// During early attribute decoding, we consider a safe subset of all members that will not /// During early attribute decoding, we consider a safe subset of all members that will not
/// cause cyclic dependencies. Get all such members for this symbol. /// cause cyclic dependencies. Get all such members for this symbol.
/// ///
/// In particular, this method will return nested types and fields (other than auto-property /// In particular, this method will return nested types and fields (other than auto-property
/// backing fields). /// backing fields).
/// </summary> /// </summary>
...@@ -1267,7 +1267,7 @@ internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers() ...@@ -1267,7 +1267,7 @@ internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers()
/// <summary> /// <summary>
/// During early attribute decoding, we consider a safe subset of all members that will not /// During early attribute decoding, we consider a safe subset of all members that will not
/// cause cyclic dependencies. Get all such members for this symbol that have a particular name. /// cause cyclic dependencies. Get all such members for this symbol that have a particular name.
/// ///
/// In particular, this method will return nested types and fields (other than auto-property /// In particular, this method will return nested types and fields (other than auto-property
/// backing fields). /// backing fields).
/// </summary> /// </summary>
...@@ -1478,23 +1478,23 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics) ...@@ -1478,23 +1478,23 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics)
// not need any special handling in this method. // not need any special handling in this method.
// //
// However, we must have special handling for conversions because conversions // However, we must have special handling for conversions because conversions
// use a completely different rule for detecting collisions between two // use a completely different rule for detecting collisions between two
// conversions: conversion signatures consist only of the source and target // conversions: conversion signatures consist only of the source and target
// types of the conversions, and not the kind of the conversion (implicit or explicit), // types of the conversions, and not the kind of the conversion (implicit or explicit),
// the name of the method, and so on. // the name of the method, and so on.
// //
// Therefore we must detect the following kinds of member name conflicts: // Therefore we must detect the following kinds of member name conflicts:
// //
// 1. a method, conversion or field has the same name as a (different) field (* see note below) // 1. a method, conversion or field has the same name as a (different) field (* see note below)
// 2. a method has the same method signature as another method or conversion // 2. a method has the same method signature as another method or conversion
// 3. a conversion has the same conversion signature as another conversion. // 3. a conversion has the same conversion signature as another conversion.
// //
// However, we must *not* detect "a conversion has the same *method* signature // However, we must *not* detect "a conversion has the same *method* signature
// as another conversion" because conversions are allowed to overload on // as another conversion" because conversions are allowed to overload on
// return type but methods are not. // return type but methods are not.
// //
// (*) NOTE: Throughout the rest of this method I will use "field" as a shorthand for // (*) NOTE: Throughout the rest of this method I will use "field" as a shorthand for
// "non-method, non-conversion, non-type member", rather than spelling out // "non-method, non-conversion, non-type member", rather than spelling out
// "field, property or event...") // "field, property or event...")
foreach (var pair in membersByName) foreach (var pair in membersByName)
...@@ -1521,7 +1521,7 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics) ...@@ -1521,7 +1521,7 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics)
// * a field directly following a field // * a field directly following a field
// * a field directly following a method or conversion // * a field directly following a method or conversion
// //
// Furthermore: we do not wish to detect collisions between nested types in // Furthermore: we do not wish to detect collisions between nested types in
// this code; that is tested elsewhere. However, we do wish to detect a collision // this code; that is tested elsewhere. However, we do wish to detect a collision
// between a nested type and a field, method or conversion. Therefore we // between a nested type and a field, method or conversion. Therefore we
// initialize our "bad transition" detector with a type of the given name, // initialize our "bad transition" detector with a type of the given name,
...@@ -1537,8 +1537,8 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics) ...@@ -1537,8 +1537,8 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics)
// //
// If either the current symbol or the "last symbol" are not methods then // If either the current symbol or the "last symbol" are not methods then
// there must be a collision: // there must be a collision:
// //
// * if the current symbol is not a method and the last symbol is, then // * if the current symbol is not a method and the last symbol is, then
// there is a field directly following a method of the same name // there is a field directly following a method of the same name
// * if the current symbol is a method and the last symbol is not, then // * if the current symbol is a method and the last symbol is not, then
// there is a method directly or indirectly following a field of the same name, // there is a method directly or indirectly following a field of the same name,
...@@ -1698,7 +1698,7 @@ private void CheckIndexerNameConflicts(DiagnosticBag diagnostics, Dictionary<str ...@@ -1698,7 +1698,7 @@ private void CheckIndexerNameConflicts(DiagnosticBag diagnostics, Dictionary<str
var indexersBySignature = new Dictionary<PropertySymbol, PropertySymbol>(MemberSignatureComparer.DuplicateSourceComparer); var indexersBySignature = new Dictionary<PropertySymbol, PropertySymbol>(MemberSignatureComparer.DuplicateSourceComparer);
// Note: Can't assume that all indexers are called WellKnownMemberNames.Indexer because // Note: Can't assume that all indexers are called WellKnownMemberNames.Indexer because
// they may be explicit interface implementations. // they may be explicit interface implementations.
foreach (var members in membersByName.Values) foreach (var members in membersByName.Values)
{ {
...@@ -1955,17 +1955,17 @@ private void CheckForProtectedInStaticClass(DiagnosticBag diagnostics) ...@@ -1955,17 +1955,17 @@ private void CheckForProtectedInStaticClass(DiagnosticBag diagnostics)
private void CheckForUnmatchedOperators(DiagnosticBag diagnostics) private void CheckForUnmatchedOperators(DiagnosticBag diagnostics)
{ {
// SPEC: The true and false unary operators require pairwise declaration. // SPEC: The true and false unary operators require pairwise declaration.
// SPEC: A compile-time error occurs if a class or struct declares one // SPEC: A compile-time error occurs if a class or struct declares one
// SPEC: of these operators without also declaring the other. // SPEC: of these operators without also declaring the other.
// //
// SPEC DEFICIENCY: The line of the specification quoted above should say // SPEC DEFICIENCY: The line of the specification quoted above should say
// the same thing as the lines below: that the formal parameters of the // the same thing as the lines below: that the formal parameters of the
// paired true/false operators must match exactly. You can't do // paired true/false operators must match exactly. You can't do
// op true(S) and op false(S?) for example. // op true(S) and op false(S?) for example.
// SPEC: Certain binary operators require pairwise declaration. For every // SPEC: Certain binary operators require pairwise declaration. For every
// SPEC: declaration of either operator of a pair, there must be a matching // SPEC: declaration of either operator of a pair, there must be a matching
// SPEC: declaration of the other operator of the pair. Two operator // SPEC: declaration of the other operator of the pair. Two operator
// SPEC: declarations match when they have the same return type and the same // SPEC: declarations match when they have the same return type and the same
// SPEC: type for each parameter. The following operators require pairwise // SPEC: type for each parameter. The following operators require pairwise
// SPEC: declaration: == and !=, > and <, >= and <=. // SPEC: declaration: == and !=, > and <, >= and <=.
...@@ -2987,9 +2987,6 @@ private void AddSynthesizedRecordMembersIfNecessary(MembersAndInitializersBuilde ...@@ -2987,9 +2987,6 @@ private void AddSynthesizedRecordMembersIfNecessary(MembersAndInitializersBuilde
diagnostics.Add(ErrorCode.ERR_BadRecordDeclaration, paramList.Location); diagnostics.Add(ErrorCode.ERR_BadRecordDeclaration, paramList.Location);
} }
BinderFactory binderFactory = this.DeclaringCompilation.GetBinderFactory(paramList.SyntaxTree);
var binder = binderFactory.GetBinder(paramList);
var ctor = addCtor(builder.RecordDeclarationWithParameters); var ctor = addCtor(builder.RecordDeclarationWithParameters);
var existingOrAddedMembers = addProperties(ctor.Parameters); var existingOrAddedMembers = addProperties(ctor.Parameters);
addDeconstruct(ctor.Parameters, existingOrAddedMembers); addDeconstruct(ctor.Parameters, existingOrAddedMembers);
...@@ -3280,8 +3277,8 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder<Symbol> members, ...@@ -3280,8 +3277,8 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder<Symbol> members,
} }
// constants don't count, since they do not exist as fields at runtime // constants don't count, since they do not exist as fields at runtime
// NOTE: even for decimal constants (which require field initializers), // NOTE: even for decimal constants (which require field initializers),
// we do not create .cctor here since a static constructor implicitly created for a decimal // we do not create .cctor here since a static constructor implicitly created for a decimal
// should not appear in the list returned by public API like GetMembers(). // should not appear in the list returned by public API like GetMembers().
if (!hasStaticConstructor && HasNonConstantInitializer(staticInitializers)) if (!hasStaticConstructor && HasNonConstantInitializer(staticInitializers))
{ {
...@@ -3438,7 +3435,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ArrayBuilder<FieldOrP ...@@ -3438,7 +3435,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ArrayBuilder<FieldOrP
// TODO: can we leave this out of the member list? // TODO: can we leave this out of the member list?
// From the 10/12/11 design notes: // From the 10/12/11 design notes:
// In addition, we will change autoproperties to behavior in // In addition, we will change autoproperties to behavior in
// a similar manner and make the autoproperty fields private. // a similar manner and make the autoproperty fields private.
if ((object)backingField != null) if ((object)backingField != null)
{ {
...@@ -3598,7 +3595,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ArrayBuilder<FieldOrP ...@@ -3598,7 +3595,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ArrayBuilder<FieldOrP
{ {
var innerStatement = globalStatement; var innerStatement = globalStatement;
// drill into any LabeledStatements // drill into any LabeledStatements
while (innerStatement.Kind() == SyntaxKind.LabeledStatement) while (innerStatement.Kind() == SyntaxKind.LabeledStatement)
{ {
innerStatement = ((LabeledStatementSyntax)innerStatement).Statement; innerStatement = ((LabeledStatementSyntax)innerStatement).Statement;
......
...@@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols ...@@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
internal partial class SourceMemberContainerTypeSymbol internal partial class SourceMemberContainerTypeSymbol
{ {
/// <summary> /// <summary>
/// In some circumstances (e.g. implicit implementation of an interface method by a non-virtual method in a /// In some circumstances (e.g. implicit implementation of an interface method by a non-virtual method in a
/// base type from another assembly) it is necessary for the compiler to generate explicit implementations for /// base type from another assembly) it is necessary for the compiler to generate explicit implementations for
/// some interface methods. They don't go in the symbol table, but if we are emitting, then we should /// some interface methods. They don't go in the symbol table, but if we are emitting, then we should
/// generate code for them. /// generate code for them.
...@@ -96,9 +96,9 @@ private void CheckAbstractClassImplementations(DiagnosticBag diagnostics) ...@@ -96,9 +96,9 @@ private void CheckAbstractClassImplementations(DiagnosticBag diagnostics)
{ {
var synthesizedImplementations = ArrayBuilder<SynthesizedExplicitImplementationForwardingMethod>.GetInstance(); var synthesizedImplementations = ArrayBuilder<SynthesizedExplicitImplementationForwardingMethod>.GetInstance();
// NOTE: We can't iterator over this collection directly, since it is not ordered. Instead we // NOTE: We can't iterator over this collection directly, since it is not ordered. Instead we
// iterate over AllInterfaces and filter out the interfaces that are not in this set. This is // iterate over AllInterfaces and filter out the interfaces that are not in this set. This is
// preferable to doing the DFS ourselves because both AllInterfaces and // preferable to doing the DFS ourselves because both AllInterfaces and
// InterfacesAndTheirBaseInterfaces are cached and used in multiple places. // InterfacesAndTheirBaseInterfaces are cached and used in multiple places.
MultiDictionary<NamedTypeSymbol, NamedTypeSymbol> interfacesAndTheirBases = this.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics; MultiDictionary<NamedTypeSymbol, NamedTypeSymbol> interfacesAndTheirBases = this.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics;
...@@ -215,8 +215,8 @@ private void CheckAbstractClassImplementations(DiagnosticBag diagnostics) ...@@ -215,8 +215,8 @@ private void CheckAbstractClassImplementations(DiagnosticBag diagnostics)
ReportAccessorOfInterfacePropertyOrEvent(associatedPropertyOrEvent) || ReportAccessorOfInterfacePropertyOrEvent(associatedPropertyOrEvent) ||
(wasImplementingMemberFound && !implementingMember.IsAccessor())) (wasImplementingMemberFound && !implementingMember.IsAccessor()))
{ {
//we're here because //we're here because
//(a) the interface member is not an accessor, or //(a) the interface member is not an accessor, or
//(b) the interface member is an accessor of an interesting (see ReportAccessorOfInterfacePropertyOrEvent) property or event, or //(b) the interface member is an accessor of an interesting (see ReportAccessorOfInterfacePropertyOrEvent) property or event, or
//(c) the implementing member exists and is not an accessor. //(c) the implementing member exists and is not an accessor.
bool reportedAnError = false; bool reportedAnError = false;
...@@ -289,14 +289,14 @@ private void CheckAbstractClassImplementations(DiagnosticBag diagnostics) ...@@ -289,14 +289,14 @@ private void CheckAbstractClassImplementations(DiagnosticBag diagnostics)
{ {
// Don't report use site errors on properties - we'll report them on each of their accessors. // Don't report use site errors on properties - we'll report them on each of their accessors.
// Don't report use site errors for implementations in other types unless // Don't report use site errors for implementations in other types unless
// a synthesized implementation is needed that invokes the base method. // a synthesized implementation is needed that invokes the base method.
// We can do so only if there are no use-site errors. // We can do so only if there are no use-site errors.
if ((object)synthesizedImplementation != null || TypeSymbol.Equals(implementingMember.ContainingType, this, TypeCompareKind.ConsiderEverything2)) if ((object)synthesizedImplementation != null || TypeSymbol.Equals(implementingMember.ContainingType, this, TypeCompareKind.ConsiderEverything2))
{ {
DiagnosticInfo useSiteDiagnostic = interfaceMember.GetUseSiteDiagnostic(); DiagnosticInfo useSiteDiagnostic = interfaceMember.GetUseSiteDiagnostic();
// CAVEAT: don't report ERR_ByRefReturnUnsupported since by-ref return types are // CAVEAT: don't report ERR_ByRefReturnUnsupported since by-ref return types are
// specifically allowed for the purposes of interface implementation (for C++ interop). // specifically allowed for the purposes of interface implementation (for C++ interop).
// However, if there's a reference to the interface member in source, then we do want // However, if there's a reference to the interface member in source, then we do want
// to produce a use site error. // to produce a use site error.
...@@ -494,7 +494,7 @@ private void HasBaseInterfaceDeclaringInterface(NamedTypeSymbol baseInterface, N ...@@ -494,7 +494,7 @@ private void HasBaseInterfaceDeclaringInterface(NamedTypeSymbol baseInterface, N
case TypeKind.Class: case TypeKind.Class:
case TypeKind.Struct: case TypeKind.Struct:
case TypeKind.Interface: case TypeKind.Interface:
case TypeKind.Submission: // we have to check that "override" is not used case TypeKind.Submission: // we have to check that "override" is not used
break; break;
default: default:
...@@ -566,7 +566,7 @@ private void HasBaseInterfaceDeclaringInterface(NamedTypeSymbol baseInterface, N ...@@ -566,7 +566,7 @@ private void HasBaseInterfaceDeclaringInterface(NamedTypeSymbol baseInterface, N
} }
} }
} }
else if (property is SourcePropertySymbol sourceProperty) else if (property is SourcePropertySymbolBase sourceProperty)
{ {
var isNewProperty = sourceProperty.IsNew; var isNewProperty = sourceProperty.IsNew;
CheckNonOverrideMember(property, isNewProperty, property.OverriddenOrHiddenMembers, diagnostics, out suppressAccessors); CheckNonOverrideMember(property, isNewProperty, property.OverriddenOrHiddenMembers, diagnostics, out suppressAccessors);
...@@ -813,11 +813,11 @@ private void CheckNewModifier(Symbol symbol, bool isNew, DiagnosticBag diagnosti ...@@ -813,11 +813,11 @@ private void CheckNewModifier(Symbol symbol, bool isNew, DiagnosticBag diagnosti
} }
// From: SymbolPreparer.cpp // From: SymbolPreparer.cpp
// DevDiv Bugs 115384: Both out and ref parameters are implemented as references. In addition, out parameters are // DevDiv Bugs 115384: Both out and ref parameters are implemented as references. In addition, out parameters are
// decorated with OutAttribute. In CLR when a signature is looked up in virtual dispatch, CLR does not distinguish // decorated with OutAttribute. In CLR when a signature is looked up in virtual dispatch, CLR does not distinguish
// between these to parameter types. The choice is the last method in the vtable. Therefore we check and warn if // between these to parameter types. The choice is the last method in the vtable. Therefore we check and warn if
// there would potentially be a mismatch in CLRs and C#s choice of the overridden method. Unfortunately we have no // there would potentially be a mismatch in CLRs and C#s choice of the overridden method. Unfortunately we have no
// way of communicating to CLR which method is the overridden one. We only run into this problem when the // way of communicating to CLR which method is the overridden one. We only run into this problem when the
// parameters are generic. // parameters are generic.
var runtimeOverriddenMembers = overriddenOrHiddenMembers.RuntimeOverriddenMembers; var runtimeOverriddenMembers = overriddenOrHiddenMembers.RuntimeOverriddenMembers;
Debug.Assert(!runtimeOverriddenMembers.IsDefault); Debug.Assert(!runtimeOverriddenMembers.IsDefault);
...@@ -1544,19 +1544,19 @@ private SynthesizedExplicitImplementationForwardingMethod SynthesizeInterfaceMem ...@@ -1544,19 +1544,19 @@ private SynthesizedExplicitImplementationForwardingMethod SynthesizeInterfaceMem
/// 1) declares that it implements that interface; or /// 1) declares that it implements that interface; or
/// 2) is a base class of a type that declares that it implements the interface but not /// 2) is a base class of a type that declares that it implements the interface but not
/// a subtype of a class that declares that it implements the interface. /// a subtype of a class that declares that it implements the interface.
/// ///
/// For example, /// For example,
/// ///
/// interface I /// interface I
/// class A /// class A
/// class B : A, I /// class B : A, I
/// class C : B /// class C : B
/// class D : C, I /// class D : C, I
/// ///
/// Suppose the runtime is looking for D's implementation of a member of I. It will look in /// Suppose the runtime is looking for D's implementation of a member of I. It will look in
/// D because of (1), will not look in C, will look in B because of (1), and will look in A /// D because of (1), will not look in C, will look in B because of (1), and will look in A
/// because of (2). /// because of (2).
/// ///
/// The key point is that it does not look in C, which C# *does*. /// The key point is that it does not look in C, which C# *does*.
/// </summary> /// </summary>
private static bool IsPossibleImplementationUnderRuntimeRules(MethodSymbol implementingMethod, NamedTypeSymbol @interface) private static bool IsPossibleImplementationUnderRuntimeRules(MethodSymbol implementingMethod, NamedTypeSymbol @interface)
...@@ -1577,7 +1577,7 @@ private static bool IsPossibleImplementationUnderRuntimeRules(MethodSymbol imple ...@@ -1577,7 +1577,7 @@ private static bool IsPossibleImplementationUnderRuntimeRules(MethodSymbol imple
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This is based on SymbolPreparer::IsCLRMethodImplSame in the native compiler. /// This is based on SymbolPreparer::IsCLRMethodImplSame in the native compiler.
/// ///
/// ACASEY: What the native compiler actually does is compute the C# answer, compute the CLR answer, /// ACASEY: What the native compiler actually does is compute the C# answer, compute the CLR answer,
/// and then confirm that they override the same method. What I've done here is check for the situations /// and then confirm that they override the same method. What I've done here is check for the situations
/// where the answers could disagree. I believe the results will be equivalent. If in doubt, a more conservative /// where the answers could disagree. I believe the results will be equivalent. If in doubt, a more conservative
......
// 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.
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal abstract class SourceOrRecordPropertySymbol : PropertySymbol, IAttributeTargetSymbol
{
public Location Location { get; }
public SourceOrRecordPropertySymbol(Location location)
{
Location = location;
}
internal abstract SynthesizedBackingFieldSymbol BackingField { get; }
internal abstract bool IsAutoProperty { get; }
internal abstract bool HasPointerType { get; }
public abstract SyntaxList<AttributeListSyntax> AttributeDeclarationSyntaxList { get; }
protected abstract IAttributeTargetSymbol AttributesOwner { get; }
protected abstract AttributeLocation AllowedAttributeLocations { get; }
protected abstract AttributeLocation DefaultAttributeLocation { get; }
IAttributeTargetSymbol IAttributeTargetSymbol.AttributesOwner => AttributesOwner;
AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations => AllowedAttributeLocations;
AttributeLocation IAttributeTargetSymbol.DefaultAttributeLocation => DefaultAttributeLocation;
}
}
...@@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols ...@@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
{ {
internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol
{ {
private readonly SourcePropertySymbol _property; private readonly SourcePropertySymbolBase _property;
private ImmutableArray<ParameterSymbol> _lazyParameters; private ImmutableArray<ParameterSymbol> _lazyParameters;
private TypeWithAnnotations _lazyReturnType; private TypeWithAnnotations _lazyReturnType;
private ImmutableArray<CustomModifier> _lazyRefCustomModifiers; private ImmutableArray<CustomModifier> _lazyRefCustomModifiers;
...@@ -53,6 +53,10 @@ internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol ...@@ -53,6 +53,10 @@ internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol
out explicitInterfaceImplementations); out explicitInterfaceImplementations);
var methodKind = isGetMethod ? MethodKind.PropertyGet : MethodKind.PropertySet; var methodKind = isGetMethod ? MethodKind.PropertyGet : MethodKind.PropertySet;
bool hasBody = syntax.Body is object;
bool hasExpressionBody = syntax.ExpressionBody is object;
CheckForBlockAndExpressionBody(syntax.Body, syntax.ExpressionBody, syntax, diagnostics);
return new SourcePropertyAccessorSymbol( return new SourcePropertyAccessorSymbol(
containingType, containingType,
name, name,
...@@ -61,7 +65,12 @@ internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol ...@@ -61,7 +65,12 @@ internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol
explicitInterfaceImplementations, explicitInterfaceImplementations,
syntax.Keyword.GetLocation(), syntax.Keyword.GetLocation(),
syntax, syntax,
hasBody,
hasExpressionBody,
isIterator: SyntaxFacts.HasYieldOperations(syntax.Body),
syntax.Modifiers,
methodKind, methodKind,
syntax.Keyword.IsKind(SyntaxKind.InitKeyword),
isAutoPropertyAccessor, isAutoPropertyAccessor,
isExplicitInterfaceImplementation, isExplicitInterfaceImplementation,
diagnostics); diagnostics);
...@@ -102,6 +111,50 @@ internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol ...@@ -102,6 +111,50 @@ internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol
diagnostics); diagnostics);
} }
#nullable enable
public static SourcePropertyAccessorSymbol CreateAccessorSymbol(
bool isGetMethod,
bool usesInit,
NamedTypeSymbol containingType,
SynthesizedRecordPropertySymbol property,
DeclarationModifiers propertyModifiers,
string propertyName,
Location location,
CSharpSyntaxNode syntax,
DiagnosticBag diagnostics)
{
string name;
ImmutableArray<MethodSymbol> explicitInterfaceImplementations;
GetNameAndExplicitInterfaceImplementations(
explicitlyImplementedPropertyOpt: null,
propertyName,
property.IsCompilationOutputWinMdObj(),
aliasQualifierOpt: null,
isGetMethod,
out name,
out explicitInterfaceImplementations);
var methodKind = isGetMethod ? MethodKind.PropertyGet : MethodKind.PropertySet;
return new SourcePropertyAccessorSymbol(
containingType,
name,
property,
propertyModifiers,
explicitInterfaceImplementations,
location,
syntax,
hasBody: false,
hasExpressionBody: false,
isIterator: false,
modifiers: new SyntaxTokenList(),
methodKind,
usesInit,
isAutoPropertyAccessor: true,
isExplicitInterfaceImplementation: false,
diagnostics);
}
#nullable restore
internal override bool IsExpressionBodied internal override bool IsExpressionBodied
=> _isExpressionBodied; => _isExpressionBodied;
...@@ -197,39 +250,43 @@ internal sealed override ImmutableArray<string> NotNullWhenFalseMembers ...@@ -197,39 +250,43 @@ internal sealed override ImmutableArray<string> NotNullWhenFalseMembers
} }
} }
#nullable enable
private SourcePropertyAccessorSymbol( private SourcePropertyAccessorSymbol(
NamedTypeSymbol containingType, NamedTypeSymbol containingType,
string name, string name,
SourcePropertySymbol property, SourcePropertySymbolBase property,
DeclarationModifiers propertyModifiers, DeclarationModifiers propertyModifiers,
ImmutableArray<MethodSymbol> explicitInterfaceImplementations, ImmutableArray<MethodSymbol> explicitInterfaceImplementations,
Location location, Location location,
AccessorDeclarationSyntax syntax, CSharpSyntaxNode syntax,
bool hasBody,
bool hasExpressionBody,
bool isIterator,
SyntaxTokenList modifiers,
MethodKind methodKind, MethodKind methodKind,
bool usesInit,
bool isAutoPropertyAccessor, bool isAutoPropertyAccessor,
bool isExplicitInterfaceImplementation, bool isExplicitInterfaceImplementation,
DiagnosticBag diagnostics) DiagnosticBag diagnostics)
: base(containingType, : base(containingType,
syntax.GetReference(), syntax.GetReference(),
location, location,
isIterator: SyntaxFacts.HasYieldOperations(syntax.Body)) isIterator: isIterator)
{ {
_property = property; _property = property;
_explicitInterfaceImplementations = explicitInterfaceImplementations; _explicitInterfaceImplementations = explicitInterfaceImplementations;
_name = name; _name = name;
_isAutoPropertyAccessor = isAutoPropertyAccessor; _isAutoPropertyAccessor = isAutoPropertyAccessor;
Debug.Assert(!_property.IsExpressionBodied, "Cannot have accessors in expression bodied lightweight properties"); Debug.Assert(!_property.IsExpressionBodied, "Cannot have accessors in expression bodied lightweight properties");
var hasBody = syntax.Body != null;
var hasExpressionBody = syntax.ExpressionBody != null;
_isExpressionBodied = !hasBody && hasExpressionBody; _isExpressionBodied = !hasBody && hasExpressionBody;
_usesInit = syntax.Keyword.IsKind(SyntaxKind.InitKeyword); _usesInit = usesInit;
if (_usesInit) if (_usesInit)
{ {
Binder.CheckFeatureAvailability(syntax, MessageID.IDS_FeatureInitOnlySetters, diagnostics, syntax.Keyword.GetLocation()); Binder.CheckFeatureAvailability(syntax, MessageID.IDS_FeatureInitOnlySetters, diagnostics, location);
} }
bool modifierErrors; bool modifierErrors;
var declarationModifiers = this.MakeModifiers(syntax, isExplicitInterfaceImplementation, hasBody || hasExpressionBody, location, diagnostics, out modifierErrors); var declarationModifiers = this.MakeModifiers(modifiers, isExplicitInterfaceImplementation, hasBody || hasExpressionBody, location, diagnostics, out modifierErrors);
// Include some modifiers from the containing property, but not the accessibility modifiers. // Include some modifiers from the containing property, but not the accessibility modifiers.
declarationModifiers |= GetAccessorModifiers(propertyModifiers) & ~DeclarationModifiers.AccessibilityMask; declarationModifiers |= GetAccessorModifiers(propertyModifiers) & ~DeclarationModifiers.AccessibilityMask;
...@@ -274,9 +331,8 @@ internal sealed override ImmutableArray<string> NotNullWhenFalseMembers ...@@ -274,9 +331,8 @@ internal sealed override ImmutableArray<string> NotNullWhenFalseMembers
} }
} }
CheckForBlockAndExpressionBody(
syntax.Body, syntax.ExpressionBody, syntax, diagnostics);
} }
#nullable restore
private static DeclarationModifiers GetAccessorModifiers(DeclarationModifiers propertyModifiers) => private static DeclarationModifiers GetAccessorModifiers(DeclarationModifiers propertyModifiers) =>
propertyModifiers & ~(DeclarationModifiers.Indexer | DeclarationModifiers.ReadOnly); propertyModifiers & ~(DeclarationModifiers.Indexer | DeclarationModifiers.ReadOnly);
...@@ -299,7 +355,7 @@ protected override void MethodChecks(DiagnosticBag diagnostics) ...@@ -299,7 +355,7 @@ protected override void MethodChecks(DiagnosticBag diagnostics)
} }
else if (this.IsOverride) else if (this.IsOverride)
{ {
// This will cause another call to SourceMethodSymbol.LazyMethodChecks, // This will cause another call to SourceMethodSymbol.LazyMethodChecks,
// but that method already handles reentrancy for exactly this case. // but that method already handles reentrancy for exactly this case.
MethodSymbol overriddenMethod = this.OverriddenMethod; MethodSymbol overriddenMethod = this.OverriddenMethod;
if ((object)overriddenMethod != null) if ((object)overriddenMethod != null)
...@@ -525,7 +581,7 @@ internal override bool IsDeclaredReadOnly ...@@ -525,7 +581,7 @@ internal override bool IsDeclaredReadOnly
internal override bool IsInitOnly => !IsStatic && _usesInit; internal override bool IsInitOnly => !IsStatic && _usesInit;
private DeclarationModifiers MakeModifiers(AccessorDeclarationSyntax syntax, bool isExplicitInterfaceImplementation, private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, bool isExplicitInterfaceImplementation,
bool hasBody, Location location, DiagnosticBag diagnostics, out bool modifierErrors) bool hasBody, Location location, DiagnosticBag diagnostics, out bool modifierErrors)
{ {
// No default accessibility. If unset, accessibility // No default accessibility. If unset, accessibility
...@@ -546,7 +602,7 @@ internal override bool IsDeclaredReadOnly ...@@ -546,7 +602,7 @@ internal override bool IsDeclaredReadOnly
defaultInterfaceImplementationModifiers = DeclarationModifiers.AccessibilityMask; defaultInterfaceImplementationModifiers = DeclarationModifiers.AccessibilityMask;
} }
var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers(syntax.Modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers(modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors);
ModifierUtils.ReportDefaultInterfaceImplementationModifiers(hasBody, mods, ModifierUtils.ReportDefaultInterfaceImplementationModifiers(hasBody, mods,
defaultInterfaceImplementationModifiers, defaultInterfaceImplementationModifiers,
...@@ -610,7 +666,8 @@ internal static string GetAccessorName(string propertyName, bool getNotSet, bool ...@@ -610,7 +666,8 @@ internal static string GetAccessorName(string propertyName, bool getNotSet, bool
} }
/// <returns> /// <returns>
/// <see cref="AccessorDeclarationSyntax"/> or <see cref="ArrowExpressionClauseSyntax"/> /// The declaring syntax for the accessor, or property if there is no accessor-specific
/// syntax.
/// </returns> /// </returns>
internal CSharpSyntaxNode GetSyntax() internal CSharpSyntaxNode GetSyntax()
{ {
...@@ -661,8 +718,17 @@ public override bool IsImplicitlyDeclared ...@@ -661,8 +718,17 @@ public override bool IsImplicitlyDeclared
get get
{ {
// Per design meeting resolution [see bug 11253], no source accessor is implicitly declared in C#, // Per design meeting resolution [see bug 11253], no source accessor is implicitly declared in C#,
// because there is "get", "set", or expression-body syntax. // if there is "get", "set", or expression-body syntax.
return false; switch (GetSyntax().Kind())
{
case SyntaxKind.GetAccessorDeclaration:
case SyntaxKind.SetAccessorDeclaration:
case SyntaxKind.InitAccessorDeclaration:
case SyntaxKind.ArrowExpressionClause:
return false;
};
return true;
} }
} }
......
...@@ -32,7 +32,7 @@ internal override FlowAnalysisAnnotations FlowAnalysisAnnotations ...@@ -32,7 +32,7 @@ internal override FlowAnalysisAnnotations FlowAnalysisAnnotations
get get
{ {
var result = FlowAnalysisAnnotations.None; var result = FlowAnalysisAnnotations.None;
if (ContainingSymbol is SourcePropertyAccessorSymbol propertyAccessor && propertyAccessor.AssociatedSymbol is SourcePropertySymbol property) if (ContainingSymbol is SourcePropertyAccessorSymbol propertyAccessor && propertyAccessor.AssociatedSymbol is SourcePropertySymbolBase property)
{ {
if (property.HasDisallowNull) if (property.HasDisallowNull)
{ {
...@@ -78,7 +78,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r ...@@ -78,7 +78,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r
{ {
base.AddSynthesizedAttributes(moduleBuilder, ref attributes); base.AddSynthesizedAttributes(moduleBuilder, ref attributes);
if (ContainingSymbol is SourcePropertyAccessorSymbol propertyAccessor && propertyAccessor.AssociatedSymbol is SourcePropertySymbol property) if (ContainingSymbol is SourcePropertyAccessorSymbol propertyAccessor && propertyAccessor.AssociatedSymbol is SourcePropertySymbolBase property)
{ {
var annotations = FlowAnalysisAnnotations; var annotations = FlowAnalysisAnnotations;
if ((annotations & FlowAnalysisAnnotations.DisallowNull) != 0) if ((annotations & FlowAnalysisAnnotations.DisallowNull) != 0)
......
...@@ -16,13 +16,13 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols ...@@ -16,13 +16,13 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
/// </summary> /// </summary>
internal sealed class SynthesizedBackingFieldSymbol : FieldSymbolWithAttributesAndModifiers internal sealed class SynthesizedBackingFieldSymbol : FieldSymbolWithAttributesAndModifiers
{ {
private readonly SourceOrRecordPropertySymbol _property; private readonly SourcePropertySymbolBase _property;
private readonly string _name; private readonly string _name;
internal bool HasInitializer { get; } internal bool HasInitializer { get; }
protected override DeclarationModifiers Modifiers { get; } protected override DeclarationModifiers Modifiers { get; }
public SynthesizedBackingFieldSymbol( public SynthesizedBackingFieldSymbol(
SourceOrRecordPropertySymbol property, SourcePropertySymbolBase property,
string name, string name,
bool isReadOnly, bool isReadOnly,
bool isStatic, bool isStatic,
......
...@@ -10232,5 +10232,22 @@ public static void Main() ...@@ -10232,5 +10232,22 @@ public static void Main()
303 303
"); ");
} }
[Fact]
public void SynthesizedRecordPointerProperty()
{
var src = @"
record R(int P1, int* P2, delegate*<int> P3);";
var comp = CreateCompilation(src);
var p = comp.GlobalNamespace.GetTypeMember("R").GetMember<SourcePropertySymbolBase>("P1");
Assert.False(p.HasPointerType);
p = comp.GlobalNamespace.GetTypeMember("R").GetMember<SourcePropertySymbolBase>("P2");
Assert.True(p.HasPointerType);
p = comp.GlobalNamespace.GetTypeMember("R").GetMember<SourcePropertySymbolBase>("P3");
Assert.True(p.HasPointerType);
}
} }
} }
...@@ -146,12 +146,13 @@ public void GeneratedProperties() ...@@ -146,12 +146,13 @@ public void GeneratedProperties()
comp.VerifyDiagnostics(); comp.VerifyDiagnostics();
var c = comp.GlobalNamespace.GetTypeMember("C"); var c = comp.GlobalNamespace.GetTypeMember("C");
var x = (SourceOrRecordPropertySymbol)c.GetProperty("x"); var x = (SourcePropertySymbolBase)c.GetProperty("x");
Assert.NotNull(x.GetMethod); Assert.NotNull(x.GetMethod);
Assert.Equal(MethodKind.PropertyGet, x.GetMethod.MethodKind); Assert.Equal(MethodKind.PropertyGet, x.GetMethod.MethodKind);
Assert.Equal(SpecialType.System_Int32, x.Type.SpecialType); Assert.Equal(SpecialType.System_Int32, x.Type.SpecialType);
Assert.False(x.IsReadOnly); Assert.False(x.IsReadOnly);
Assert.False(x.IsWriteOnly); Assert.False(x.IsWriteOnly);
Assert.False(x.IsImplicitlyDeclared);
Assert.Equal(Accessibility.Public, x.DeclaredAccessibility); Assert.Equal(Accessibility.Public, x.DeclaredAccessibility);
Assert.False(x.IsVirtual); Assert.False(x.IsVirtual);
Assert.False(x.IsStatic); Assert.False(x.IsStatic);
...@@ -162,26 +163,30 @@ public void GeneratedProperties() ...@@ -162,26 +163,30 @@ public void GeneratedProperties()
Assert.Equal(x, backing.AssociatedSymbol); Assert.Equal(x, backing.AssociatedSymbol);
Assert.Equal(c, backing.ContainingSymbol); Assert.Equal(c, backing.ContainingSymbol);
Assert.Equal(c, backing.ContainingType); Assert.Equal(c, backing.ContainingType);
Assert.True(backing.IsImplicitlyDeclared);
var getAccessor = x.GetMethod; var getAccessor = x.GetMethod;
Assert.Equal(x, getAccessor.AssociatedSymbol); Assert.Equal(x, getAccessor.AssociatedSymbol);
Assert.True(getAccessor.IsImplicitlyDeclared);
Assert.Equal(c, getAccessor.ContainingSymbol); Assert.Equal(c, getAccessor.ContainingSymbol);
Assert.Equal(c, getAccessor.ContainingType); Assert.Equal(c, getAccessor.ContainingType);
Assert.Equal(Accessibility.Public, getAccessor.DeclaredAccessibility); Assert.Equal(Accessibility.Public, getAccessor.DeclaredAccessibility);
var setAccessor = x.SetMethod; var setAccessor = x.SetMethod;
Assert.Equal(x, setAccessor.AssociatedSymbol); Assert.Equal(x, setAccessor.AssociatedSymbol);
Assert.True(setAccessor.IsImplicitlyDeclared);
Assert.Equal(c, setAccessor.ContainingSymbol); Assert.Equal(c, setAccessor.ContainingSymbol);
Assert.Equal(c, setAccessor.ContainingType); Assert.Equal(c, setAccessor.ContainingType);
Assert.Equal(Accessibility.Public, setAccessor.DeclaredAccessibility); Assert.Equal(Accessibility.Public, setAccessor.DeclaredAccessibility);
Assert.True(setAccessor.IsInitOnly); Assert.True(setAccessor.IsInitOnly);
var y = (SourceOrRecordPropertySymbol)c.GetProperty("y"); var y = (SourcePropertySymbolBase)c.GetProperty("y");
Assert.NotNull(y.GetMethod); Assert.NotNull(y.GetMethod);
Assert.Equal(MethodKind.PropertyGet, y.GetMethod.MethodKind); Assert.Equal(MethodKind.PropertyGet, y.GetMethod.MethodKind);
Assert.Equal(SpecialType.System_Int32, y.Type.SpecialType); Assert.Equal(SpecialType.System_Int32, y.Type.SpecialType);
Assert.False(y.IsReadOnly); Assert.False(y.IsReadOnly);
Assert.False(y.IsWriteOnly); Assert.False(y.IsWriteOnly);
Assert.False(y.IsImplicitlyDeclared);
Assert.Equal(Accessibility.Public, y.DeclaredAccessibility); Assert.Equal(Accessibility.Public, y.DeclaredAccessibility);
Assert.False(x.IsVirtual); Assert.False(x.IsVirtual);
Assert.False(x.IsStatic); Assert.False(x.IsStatic);
...@@ -192,14 +197,17 @@ public void GeneratedProperties() ...@@ -192,14 +197,17 @@ public void GeneratedProperties()
Assert.Equal(y, backing.AssociatedSymbol); Assert.Equal(y, backing.AssociatedSymbol);
Assert.Equal(c, backing.ContainingSymbol); Assert.Equal(c, backing.ContainingSymbol);
Assert.Equal(c, backing.ContainingType); Assert.Equal(c, backing.ContainingType);
Assert.True(backing.IsImplicitlyDeclared);
getAccessor = y.GetMethod; getAccessor = y.GetMethod;
Assert.Equal(y, getAccessor.AssociatedSymbol); Assert.Equal(y, getAccessor.AssociatedSymbol);
Assert.True(getAccessor.IsImplicitlyDeclared);
Assert.Equal(c, getAccessor.ContainingSymbol); Assert.Equal(c, getAccessor.ContainingSymbol);
Assert.Equal(c, getAccessor.ContainingType); Assert.Equal(c, getAccessor.ContainingType);
setAccessor = y.SetMethod; setAccessor = y.SetMethod;
Assert.Equal(y, setAccessor.AssociatedSymbol); Assert.Equal(y, setAccessor.AssociatedSymbol);
Assert.True(setAccessor.IsImplicitlyDeclared);
Assert.Equal(c, setAccessor.ContainingSymbol); Assert.Equal(c, setAccessor.ContainingSymbol);
Assert.Equal(c, setAccessor.ContainingType); Assert.Equal(c, setAccessor.ContainingType);
Assert.Equal(Accessibility.Public, setAccessor.DeclaredAccessibility); Assert.Equal(Accessibility.Public, setAccessor.DeclaredAccessibility);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册