未验证 提交 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
#nullable enable
/// <summary>
/// Bind the syntax into a namespace, type or alias symbol.
/// Bind the syntax into a namespace, type or alias symbol.
/// </summary>
/// <remarks>
/// This method is used in deeply recursive parts of the compiler. Specifically this and
/// <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"/>.
///
/// 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
/// enough they should be disqualified from inlining. In the future when attributes are allowed on
/// 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
/// 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"/>
/// </remarks>
internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasSymbol(ExpressionSyntax syntax, DiagnosticBag diagnostics, ConsList<TypeSymbol> basesBeingResolved, bool suppressUseSiteDiagnostics)
......@@ -757,7 +757,7 @@ private NamedTypeSymbol BindPredefinedTypeSymbol(PredefinedTypeSyntax node, Diag
}
/// <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>
private NamespaceOrTypeOrAliasSymbolWithAnnotations BindSimpleNamespaceOrTypeOrAliasSymbol(
SimpleNameSyntax syntax,
......@@ -766,10 +766,10 @@ private NamedTypeSymbol BindPredefinedTypeSymbol(PredefinedTypeSyntax node, Diag
bool suppressUseSiteDiagnostics,
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
// "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
// side is in qualifierOpt.
......@@ -819,7 +819,7 @@ private static bool IsViableType(LookupResult result)
var identifierValueText = node.Identifier.ValueText;
// 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
// just bail out with an error symbol.
......@@ -945,9 +945,9 @@ private static LookupOptions GetSimpleNameLookupOptions(NameSyntax node, bool is
{
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: 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: 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.
......@@ -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
// 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.
// 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
// 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
// * Lookup could fail to find anything at all.
// * Lookup could find a type of the wrong arity
// * Lookup could find something but it is not a type.
//
//
// 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
// intended an improvement over the analysis performed by the
// native compiler; in the native compiler we catch bad uses of unbound
// not in a context where it is legal to do so. Note that this is
// intended an improvement over the analysis performed by the
// native compiler; in the native compiler we catch bad uses of unbound
// types at parse time, not at semantic analysis time. That means that
// we end up giving confusing "unexpected comma" or "expected type"
// 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
// 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
// a partially unbound type.
//
// 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,
// 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
// deduce more errors from it.
// mean by the remainder ".Blah<int>" of the expression and so it seems wrong to
// deduce more errors from it.
var plainName = node.Identifier.ValueText;
......@@ -1114,9 +1114,9 @@ private Symbol UnwrapAlias(Symbol symbol, out AliasSymbol alias, DiagnosticBag d
}
else
{
// 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
// arguments and construct the final result.
// 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
// arguments and construct the final result.
resultType = ConstructNamedType(
unconstructedType,
node,
......@@ -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 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 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.
// (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;
......@@ -1489,7 +1489,16 @@ internal static bool ReportUseSiteDiagnostics(Symbol symbol, DiagnosticBag diagn
/// </summary>
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>
......@@ -1892,7 +1901,7 @@ public int Compare(Symbol fst, Symbol snd)
Compilation.IsAttributeType((NamedTypeSymbol)first) &&
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.
info = new CSDiagnosticInfo(ErrorCode.ERR_AmbiguousAttribute, originalSymbols,
......@@ -1960,7 +1969,7 @@ public int Compare(Symbol fst, Symbol snd)
}
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.
var errorType = (ErrorTypeSymbol)singleResult;
......@@ -2341,7 +2350,7 @@ protected AssemblySymbol GetForwardedToAssembly(string fullName, DiagnosticBag d
/// <param name="name">The name of the (potentially) 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
/// 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>
/// <param name="diagnostics">Will be used to report non-fatal errors during look up.</param>
/// <param name="location">Location to report errors on.</param>
......@@ -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 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
// might require us to examine types forwarded by this assembly, thus binding assembly level
// attributes again. And the cycle continues.
// might require us to examine types forwarded by this assembly, thus binding assembly level
// attributes again. And the cycle continues.
// So, we won't do the analysis in this case, at the expense of better diagnostics.
if ((this.Flags & BinderFlags.InContextualAttributeBinder) != 0)
{
......
......@@ -12,7 +12,7 @@
namespace Microsoft.CodeAnalysis.CSharp
{
/// <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.
/// </summary>
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.
//
// 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.
// 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.
// For this reason Script class must always derive directly from a class that has no state (System.Object).
SyntaxNode syntax = loweredBody.Syntax;
......@@ -172,7 +172,7 @@ internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMemberMethodS
{
Debug.Assert(accessor.MethodKind == MethodKind.PropertyGet || accessor.MethodKind == MethodKind.PropertySet);
var property = (SourcePropertySymbol)accessor.AssociatedSymbol;
var property = (SourcePropertySymbolBase)accessor.AssociatedSymbol;
CSharpSyntaxNode syntax = property.CSharpSyntaxNode;
BoundExpression thisReference = null;
if (!accessor.IsStatic)
......@@ -219,10 +219,10 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody(SourceEventSymbol
/// <summary>
/// Generate a thread-safe accessor for a WinRT field-like event.
///
///
/// Add:
/// return EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value);
///
///
/// Remove:
/// EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value);
/// </summary>
......@@ -302,7 +302,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent
{
// {
// return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value);
// }
// }
BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, RefKind.None, processHandlerCall);
return BoundBlock.SynthesizedNoLocals(syntax, returnStatement);
}
......@@ -311,7 +311,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent
// {
// EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value);
// return;
// }
// }
BoundStatement callStatement = new BoundExpressionStatement(syntax, processHandlerCall);
BoundStatement returnStatement = new BoundReturnStatement(syntax, RefKind.None, expressionOpt: null);
return BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement);
......@@ -320,7 +320,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent
/// <summary>
/// Generate a thread-safe accessor for a regular field-like event.
///
///
/// DelegateType tmp0 = _event; //backing field
/// DelegateType tmp1;
/// DelegateType tmp2;
......@@ -329,12 +329,12 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent
/// tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -=
/// tmp0 = Interlocked.CompareExchange&lt;DelegateType&gt;(ref _event, tmp2, tmp1);
/// } while ((object)tmp0 != (object)tmp1);
///
///
/// 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).
///
///
/// _event = (DelegateType)Delegate.Combine(_event, value); //Remove for -=
///
///
/// </summary>
internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
{
......@@ -522,7 +522,7 @@ internal static BoundBlock ConstructDestructorBody(MethodSymbol method, BoundBlo
Debug.Assert(method.MethodKind == MethodKind.Destructor);
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.
// NOTE: the Finalize method need not be a destructor or be overridden by the current method.
MethodSymbol baseTypeFinalize = GetBaseTypeFinalizeMethod(method);
......@@ -572,11 +572,11 @@ internal static BoundBlock ConstructDestructorBody(MethodSymbol method, BoundBlo
}
/// <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.
/// </summary>
/// <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).
/// </remarks>
private static MethodSymbol GetBaseTypeFinalizeMethod(MethodSymbol method)
......
......@@ -39,16 +39,16 @@ internal sealed class MethodCompiler : CSharpSymbolVisitor<TypeCompilationState,
// MethodCompiler employs concurrency by following flattened fork/join pattern.
//
// 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)
// 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),
// 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
// 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.
private ConcurrentStack<Task> _compilerTasks;
......@@ -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.
// Such races are unavoidable and will just result in performing some work that is safe to do
// 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.
if (arg)
{
......@@ -119,7 +119,7 @@ private void SetGlobalErrorIfTrue(bool arg)
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
// NOTE: if there are any errors, we will pick up what was created anyway
......@@ -515,7 +515,7 @@ private void CompileNamedType(NamedTypeSymbol containingType)
case SymbolKind.Property:
{
SourcePropertySymbol sourceProperty = member as SourcePropertySymbol;
var sourceProperty = member as SourcePropertySymbolBase;
if ((object)sourceProperty != null && sourceProperty.IsSealed && compilationState.Emitting)
{
CompileSynthesizedSealedAccessors(sourceProperty, compilationState);
......@@ -690,7 +690,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
var importChain = methodWithBody.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
// any diagnostics emitted into it back into the main diagnostic bag.
var diagnosticsThisMethod = DiagnosticBag.GetInstance();
......@@ -702,7 +702,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
_moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(method, method, diagnosticsThisMethod);
// 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.
const int methodOrdinal = -1;
MethodBody emittedBody = null;
......@@ -775,7 +775,7 @@ private static bool IsFieldLikeEventAccessor(MethodSymbol method)
}
/// <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
/// some interface methods. They don't go in the symbol table, but if we are emitting, then we should
/// generate code for them.
......@@ -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;
......@@ -991,9 +991,9 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
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
// (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.
if (includeInitializersInBody && processedInitializers.LoweredInitializers == null)
{
......@@ -1098,7 +1098,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
_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.
if (_moduleBeingBuiltOpt == null || hasErrors)
{
......@@ -1108,7 +1108,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
// ############################
// 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()
ImmutableArray<SourceSpan> dynamicAnalysisSpans = ImmutableArray<SourceSpan>.Empty;
......@@ -1320,9 +1320,9 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
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.
// 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
// if these locals are captured into closures (possibly nested ones).
loweredBody = AsyncExceptionHandlerRewriter.Rewrite(
......@@ -1442,7 +1442,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
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).
kickoffMethod = kickoffMethod.PartialDefinitionPart ?? kickoffMethod;
}
......@@ -1488,7 +1488,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
var stateMachineHoistedLocalScopes = ((object)kickoffMethod != null) ?
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.
// 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);
......@@ -1722,7 +1722,7 @@ internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationSt
}
else
{
var property = sourceMethod.AssociatedSymbol as SourcePropertySymbol;
var property = sourceMethod.AssociatedSymbol as SourcePropertySymbolBase;
if ((object)property != null && property.IsAutoProperty)
{
return MethodBodySynthesizer.ConstructAutoPropertyAccessorBody(sourceMethod);
......@@ -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
// 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
// there is no need to look up "x".
Binder outerBinder;
......@@ -1871,7 +1871,7 @@ private static void ReportCtorInitializerCycles(MethodSymbol method, BoundExpres
if ((object)sourceConstructor == null)
{
// 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();
BinderFactory binderFactory = compilation.GetBinderFactory(containerNode.SyntaxTree);
......
......@@ -14,9 +14,9 @@
namespace Microsoft.CodeAnalysis.CSharp
{
/// <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.
/// 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
/// </summary>
internal sealed class SynthesizedMetadataCompiler : CSharpSymbolVisitor
......@@ -66,7 +66,7 @@ public override void VisitNamedType(NamedTypeSymbol symbol)
{
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
// 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.
......@@ -91,7 +91,7 @@ public override void VisitNamedType(NamedTypeSymbol symbol)
public override void VisitProperty(PropertySymbol symbol)
{
var sourceProperty = symbol as SourcePropertySymbol;
var sourceProperty = symbol as SourcePropertySymbolBase;
if ((object)sourceProperty != null && sourceProperty.IsSealed)
{
var synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt;
......
......@@ -33,7 +33,7 @@ IEnumerable<IMethodReference> IPropertyDefinition.GetAccessors(EmitContext conte
yield return setMethod;
}
SourcePropertySymbol sourceProperty = this as SourcePropertySymbol;
var sourceProperty = this as SourcePropertySymbolBase;
if ((object)sourceProperty != null && sourceProperty.ShouldInclude(context))
{
SynthesizedSealedPropertyAccessor synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt;
......@@ -266,7 +266,7 @@ string INamedEntity.Name
private IMethodReference GetSynthesizedSealedAccessor(MethodKind targetMethodKind)
{
SourcePropertySymbol sourceProperty = this as SourcePropertySymbol;
var sourceProperty = this as SourcePropertySymbolBase;
if ((object)sourceProperty != null)
{
SynthesizedSealedPropertyAccessor synthesized = sourceProperty.SynthesizedSealedAccessorOpt;
......
......@@ -563,7 +563,7 @@ protected void VisitLvalue(BoundExpression node)
if (Binder.AccessingAutoPropertyFromConstructor(access, _symbol))
{
var backingField = (access.PropertySymbol as SourcePropertySymbol)?.BackingField;
var backingField = (access.PropertySymbol as SourcePropertySymbolBase)?.BackingField;
if (backingField != null)
{
VisitFieldAccessInternal(access.ReceiverOpt, backingField);
......@@ -1077,7 +1077,7 @@ public override BoundNode VisitStringInsert(BoundStringInsert 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.
return null;
}
......@@ -1576,7 +1576,7 @@ public override BoundNode VisitTryStatement(BoundTryStatement node)
RestorePending(pendingBeforeTry);
// 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.
//
// 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
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
// and accessed in a corresponding constructor
private bool RegularPropertyAccess(BoundExpression expr)
......@@ -1958,7 +1958,7 @@ public override BoundNode VisitPropertyAccess(BoundPropertyAccess node)
if (Binder.AccessingAutoPropertyFromConstructor(node, _symbol))
{
var backingField = (property as SourcePropertySymbol)?.BackingField;
var backingField = (property as SourcePropertySymbolBase)?.BackingField;
if (backingField != null)
{
VisitFieldAccessInternal(node.ReceiverOpt, backingField);
......@@ -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,
// 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
// 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
// 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.
TLocalState initialState = this.State.Clone();
Visit(blockBody);
......
......@@ -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
// 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
// discarded is written into a local variable so that it can be
// easily inspected in the debugger.
//
//
// * An otherwise unread local variable that contains a reference to an
// object can keep the object alive longer, particularly if the jitter
// is not optimizing the lifetimes of locals. (Because, for example,
......@@ -597,7 +597,7 @@ protected virtual void NoteWrite(Symbol variable, BoundExpression value, bool re
// the developer to more easily examine its state.
//
// * 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();"
//
// 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)
if ((object)type != null && type.IsPointerOrFunctionPointer())
{
// We always suppress the warning for pointer types.
// We always suppress the warning for pointer types.
return true;
}
......@@ -798,7 +798,7 @@ protected override bool TryGetReceiverAndMember(BoundExpression expr, out BoundE
if (Binder.AccessingAutoPropertyFromConstructor(propAccess, this.CurrentSymbol))
{
var propSymbol = propAccess.PropertySymbol;
member = (propSymbol as SourcePropertySymbol)?.BackingField;
member = (propSymbol as SourcePropertySymbolBase)?.BackingField;
if (member is null)
{
return false;
......@@ -1023,7 +1023,7 @@ private bool IsAssigned(BoundExpression node, out int unassignedSlot)
if (Binder.AccessingAutoPropertyFromConstructor(propertyAccess, this.CurrentSymbol))
{
var property = propertyAccess.PropertySymbol;
var backingField = (property as SourcePropertySymbol)?.BackingField;
var backingField = (property as SourcePropertySymbolBase)?.BackingField;
if (backingField != null)
{
if (!MayRequireTracking(propertyAccess.ReceiverOpt, backingField) || IsAssigned(propertyAccess.ReceiverOpt, out unassignedSlot))
......@@ -2036,7 +2036,7 @@ public override BoundNode VisitPropertyAccess(BoundPropertyAccess node)
if (Binder.AccessingAutoPropertyFromConstructor(node, this.CurrentSymbol))
{
var property = node.PropertySymbol;
var backingField = (property as SourcePropertySymbol)?.BackingField;
var backingField = (property as SourcePropertySymbolBase)?.BackingField;
if (backingField != null)
{
if (MayRequireTracking(node.ReceiverOpt, backingField))
......
......@@ -7039,14 +7039,14 @@ static FlowAnalysisAnnotations getSetterAnnotations(PropertySymbol property)
{
return accessor.Parameters.Last().FlowAnalysisAnnotations;
}
if (property is SourcePropertySymbol sourceProperty)
if (property is SourcePropertySymbolBase sourceProperty)
{
return getPropertyAnnotations(sourceProperty);
}
return FlowAnalysisAnnotations.None;
}
static FlowAnalysisAnnotations getPropertyAnnotations(SourcePropertySymbol property)
static FlowAnalysisAnnotations getPropertyAnnotations(SourcePropertySymbolBase property)
{
var annotations = FlowAnalysisAnnotations.None;
if (property.HasAllowNull)
......
......@@ -300,7 +300,7 @@ private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bo
if (setMethod is null)
{
var autoProp = (SourceOrRecordPropertySymbol)property;
var autoProp = (SourcePropertySymbolBase)property;
Debug.Assert(autoProp.IsAutoProperty,
"only autoproperties can be assignable without having setters");
......
......@@ -104,7 +104,7 @@ private static bool ShouldMethodDisplayReadOnly(IMethodSymbol method, IPropertyS
}
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
return sourceAccessor.LocalDeclaredReadOnly || sourceProperty.HasReadOnlyModifier;
......@@ -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
// symbol then we do not know its accessibility, modifiers, etc, all of which require knowing
// the containing type, so we'll skip them.
......@@ -343,7 +343,7 @@ public override void VisitMethod(IMethodSymbol symbol)
break;
case MethodKind.Destructor:
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
// signature.
if (format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames))
......@@ -354,8 +354,8 @@ public override void VisitMethod(IMethodSymbol symbol)
break;
default:
// 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
// still be null.
// to visualize a symbol *during its construction*, the parameters and return type might
// still be null.
if (symbol.ReturnsByRef)
{
......@@ -777,8 +777,8 @@ private void AddParametersIfRequired(bool hasThisParameter, bool isVarargs, Immu
var first = true;
// 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
// still be null.
// to visualize a symbol *during its construction*, the parameters and return type might
// still be null.
if (!parameters.IsDefault)
{
......
......@@ -986,7 +986,7 @@ internal bool TryCalculateSyntaxOffsetOfPositionInInitializer(int position, Synt
// |<-----------distanceFromCtorBody----------->|
// [ initializer 0 ][ initializer 1 ][ initializer 2 ][ctor initializer][ctor body]
// |<--preceding init len-->| ^
// position
// position
int initializersLength = isStatic ? membersAndInitializers.StaticInitializersSyntaxLength : membersAndInitializers.InstanceInitializersSyntaxLength;
int distanceFromInitializerStart = position - siblingInitializers[index].Syntax.Span.Start;
......@@ -1255,7 +1255,7 @@ internal override IEnumerable<FieldSymbol> GetFieldsToEmit()
/// <summary>
/// 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.
///
///
/// In particular, this method will return nested types and fields (other than auto-property
/// backing fields).
/// </summary>
......@@ -1267,7 +1267,7 @@ internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers()
/// <summary>
/// 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.
///
///
/// In particular, this method will return nested types and fields (other than auto-property
/// backing fields).
/// </summary>
......@@ -1478,23 +1478,23 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics)
// not need any special handling in this method.
//
// 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
// types of the conversions, and not the kind of the conversion (implicit or explicit),
// the name of the method, and so on.
//
// 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
// 3. a conversion has the same conversion signature as another conversion.
//
// However, we must *not* detect "a conversion has the same *method* signature
// as another conversion" because conversions are allowed to overload on
// However, we must *not* detect "a conversion has the same *method* signature
// as another conversion" because conversions are allowed to overload on
// return type but methods are not.
//
// (*) 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...")
foreach (var pair in membersByName)
......@@ -1521,7 +1521,7 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics)
// * a field directly following a field
// * 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
// between a nested type and a field, method or conversion. Therefore we
// initialize our "bad transition" detector with a type of the given name,
......@@ -1537,8 +1537,8 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics)
//
// If either the current symbol or the "last symbol" are not methods then
// 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
// * 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,
......@@ -1698,7 +1698,7 @@ private void CheckIndexerNameConflicts(DiagnosticBag diagnostics, Dictionary<str
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.
foreach (var members in membersByName.Values)
{
......@@ -1955,17 +1955,17 @@ private void CheckForProtectedInStaticClass(DiagnosticBag diagnostics)
private void CheckForUnmatchedOperators(DiagnosticBag diagnostics)
{
// 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 DEFICIENCY: The line of the specification quoted above should say
// 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.
// 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 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: type for each parameter. The following operators require pairwise
// SPEC: declaration: == and !=, > and <, >= and <=.
......@@ -2987,9 +2987,6 @@ private void AddSynthesizedRecordMembersIfNecessary(MembersAndInitializersBuilde
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 existingOrAddedMembers = addProperties(ctor.Parameters);
addDeconstruct(ctor.Parameters, existingOrAddedMembers);
......@@ -3280,8 +3277,8 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder<Symbol> members,
}
// constants don't count, since they do not exist as fields at runtime
// NOTE: even for decimal constants (which require field initializers),
// we do not create .cctor here since a static constructor implicitly created for a decimal
// NOTE: even for decimal constants (which require field initializers),
// 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().
if (!hasStaticConstructor && HasNonConstantInitializer(staticInitializers))
{
......@@ -3438,7 +3435,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ArrayBuilder<FieldOrP
// TODO: can we leave this out of the member list?
// 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.
if ((object)backingField != null)
{
......@@ -3598,7 +3595,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ArrayBuilder<FieldOrP
{
var innerStatement = globalStatement;
// drill into any LabeledStatements
// drill into any LabeledStatements
while (innerStatement.Kind() == SyntaxKind.LabeledStatement)
{
innerStatement = ((LabeledStatementSyntax)innerStatement).Statement;
......
......@@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
internal partial class SourceMemberContainerTypeSymbol
{
/// <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
/// some interface methods. They don't go in the symbol table, but if we are emitting, then we should
/// generate code for them.
......@@ -96,9 +96,9 @@ private void CheckAbstractClassImplementations(DiagnosticBag diagnostics)
{
var synthesizedImplementations = ArrayBuilder<SynthesizedExplicitImplementationForwardingMethod>.GetInstance();
// 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
// preferable to doing the DFS ourselves because both AllInterfaces and
// 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
// preferable to doing the DFS ourselves because both AllInterfaces and
// InterfacesAndTheirBaseInterfaces are cached and used in multiple places.
MultiDictionary<NamedTypeSymbol, NamedTypeSymbol> interfacesAndTheirBases = this.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics;
......@@ -215,8 +215,8 @@ private void CheckAbstractClassImplementations(DiagnosticBag diagnostics)
ReportAccessorOfInterfacePropertyOrEvent(associatedPropertyOrEvent) ||
(wasImplementingMemberFound && !implementingMember.IsAccessor()))
{
//we're here because
//(a) the interface member is not an accessor, or
//we're here because
//(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
//(c) the implementing member exists and is not an accessor.
bool reportedAnError = false;
......@@ -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 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.
// We can do so only if there are no use-site errors.
if ((object)synthesizedImplementation != null || TypeSymbol.Equals(implementingMember.ContainingType, this, TypeCompareKind.ConsiderEverything2))
{
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).
// However, if there's a reference to the interface member in source, then we do want
// to produce a use site error.
......@@ -494,7 +494,7 @@ private void HasBaseInterfaceDeclaringInterface(NamedTypeSymbol baseInterface, N
case TypeKind.Class:
case TypeKind.Struct:
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;
default:
......@@ -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;
CheckNonOverrideMember(property, isNewProperty, property.OverriddenOrHiddenMembers, diagnostics, out suppressAccessors);
......@@ -813,11 +813,11 @@ private void CheckNewModifier(Symbol symbol, bool isNew, DiagnosticBag diagnosti
}
// 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
// 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
// way of communicating to CLR which method is the overridden one. We only run into this problem when the
// 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
// way of communicating to CLR which method is the overridden one. We only run into this problem when the
// parameters are generic.
var runtimeOverriddenMembers = overriddenOrHiddenMembers.RuntimeOverriddenMembers;
Debug.Assert(!runtimeOverriddenMembers.IsDefault);
......@@ -1544,19 +1544,19 @@ private SynthesizedExplicitImplementationForwardingMethod SynthesizeInterfaceMem
/// 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
/// a subtype of a class that declares that it implements the interface.
///
///
/// For example,
///
///
/// interface I
/// class A
/// class B : A, I
/// class C : B
/// 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
/// because of (2).
///
///
/// The key point is that it does not look in C, which C# *does*.
/// </summary>
private static bool IsPossibleImplementationUnderRuntimeRules(MethodSymbol implementingMethod, NamedTypeSymbol @interface)
......@@ -1577,7 +1577,7 @@ private static bool IsPossibleImplementationUnderRuntimeRules(MethodSymbol imple
/// </summary>
/// <remarks>
/// 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,
/// 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
......
// 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
{
internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol
{
private readonly SourcePropertySymbol _property;
private readonly SourcePropertySymbolBase _property;
private ImmutableArray<ParameterSymbol> _lazyParameters;
private TypeWithAnnotations _lazyReturnType;
private ImmutableArray<CustomModifier> _lazyRefCustomModifiers;
......@@ -53,6 +53,10 @@ internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol
out explicitInterfaceImplementations);
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(
containingType,
name,
......@@ -61,7 +65,12 @@ internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol
explicitInterfaceImplementations,
syntax.Keyword.GetLocation(),
syntax,
hasBody,
hasExpressionBody,
isIterator: SyntaxFacts.HasYieldOperations(syntax.Body),
syntax.Modifiers,
methodKind,
syntax.Keyword.IsKind(SyntaxKind.InitKeyword),
isAutoPropertyAccessor,
isExplicitInterfaceImplementation,
diagnostics);
......@@ -102,6 +111,50 @@ internal sealed class SourcePropertyAccessorSymbol : SourceMemberMethodSymbol
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
=> _isExpressionBodied;
......@@ -197,39 +250,43 @@ internal sealed override ImmutableArray<string> NotNullWhenFalseMembers
}
}
#nullable enable
private SourcePropertyAccessorSymbol(
NamedTypeSymbol containingType,
string name,
SourcePropertySymbol property,
SourcePropertySymbolBase property,
DeclarationModifiers propertyModifiers,
ImmutableArray<MethodSymbol> explicitInterfaceImplementations,
Location location,
AccessorDeclarationSyntax syntax,
CSharpSyntaxNode syntax,
bool hasBody,
bool hasExpressionBody,
bool isIterator,
SyntaxTokenList modifiers,
MethodKind methodKind,
bool usesInit,
bool isAutoPropertyAccessor,
bool isExplicitInterfaceImplementation,
DiagnosticBag diagnostics)
: base(containingType,
syntax.GetReference(),
location,
isIterator: SyntaxFacts.HasYieldOperations(syntax.Body))
isIterator: isIterator)
{
_property = property;
_explicitInterfaceImplementations = explicitInterfaceImplementations;
_name = name;
_isAutoPropertyAccessor = isAutoPropertyAccessor;
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;
_usesInit = syntax.Keyword.IsKind(SyntaxKind.InitKeyword);
_usesInit = usesInit;
if (_usesInit)
{
Binder.CheckFeatureAvailability(syntax, MessageID.IDS_FeatureInitOnlySetters, diagnostics, syntax.Keyword.GetLocation());
Binder.CheckFeatureAvailability(syntax, MessageID.IDS_FeatureInitOnlySetters, diagnostics, location);
}
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.
declarationModifiers |= GetAccessorModifiers(propertyModifiers) & ~DeclarationModifiers.AccessibilityMask;
......@@ -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) =>
propertyModifiers & ~(DeclarationModifiers.Indexer | DeclarationModifiers.ReadOnly);
......@@ -299,7 +355,7 @@ protected override void MethodChecks(DiagnosticBag diagnostics)
}
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.
MethodSymbol overriddenMethod = this.OverriddenMethod;
if ((object)overriddenMethod != null)
......@@ -525,7 +581,7 @@ internal override bool IsDeclaredReadOnly
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)
{
// No default accessibility. If unset, accessibility
......@@ -546,7 +602,7 @@ internal override bool IsDeclaredReadOnly
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,
defaultInterfaceImplementationModifiers,
......@@ -610,7 +666,8 @@ internal static string GetAccessorName(string propertyName, bool getNotSet, bool
}
/// <returns>
/// <see cref="AccessorDeclarationSyntax"/> or <see cref="ArrowExpressionClauseSyntax"/>
/// The declaring syntax for the accessor, or property if there is no accessor-specific
/// syntax.
/// </returns>
internal CSharpSyntaxNode GetSyntax()
{
......@@ -661,8 +718,17 @@ public override bool IsImplicitlyDeclared
get
{
// Per design meeting resolution [see bug 11253], no source accessor is implicitly declared in C#,
// because there is "get", "set", or expression-body syntax.
return false;
// if there is "get", "set", or expression-body syntax.
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
get
{
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)
{
......@@ -78,7 +78,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r
{
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;
if ((annotations & FlowAnalysisAnnotations.DisallowNull) != 0)
......
......@@ -16,13 +16,13 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
/// </summary>
internal sealed class SynthesizedBackingFieldSymbol : FieldSymbolWithAttributesAndModifiers
{
private readonly SourceOrRecordPropertySymbol _property;
private readonly SourcePropertySymbolBase _property;
private readonly string _name;
internal bool HasInitializer { get; }
protected override DeclarationModifiers Modifiers { get; }
public SynthesizedBackingFieldSymbol(
SourceOrRecordPropertySymbol property,
SourcePropertySymbolBase property,
string name,
bool isReadOnly,
bool isStatic,
......
......@@ -10232,5 +10232,22 @@ public static void Main()
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()
comp.VerifyDiagnostics();
var c = comp.GlobalNamespace.GetTypeMember("C");
var x = (SourceOrRecordPropertySymbol)c.GetProperty("x");
var x = (SourcePropertySymbolBase)c.GetProperty("x");
Assert.NotNull(x.GetMethod);
Assert.Equal(MethodKind.PropertyGet, x.GetMethod.MethodKind);
Assert.Equal(SpecialType.System_Int32, x.Type.SpecialType);
Assert.False(x.IsReadOnly);
Assert.False(x.IsWriteOnly);
Assert.False(x.IsImplicitlyDeclared);
Assert.Equal(Accessibility.Public, x.DeclaredAccessibility);
Assert.False(x.IsVirtual);
Assert.False(x.IsStatic);
......@@ -162,26 +163,30 @@ public void GeneratedProperties()
Assert.Equal(x, backing.AssociatedSymbol);
Assert.Equal(c, backing.ContainingSymbol);
Assert.Equal(c, backing.ContainingType);
Assert.True(backing.IsImplicitlyDeclared);
var getAccessor = x.GetMethod;
Assert.Equal(x, getAccessor.AssociatedSymbol);
Assert.True(getAccessor.IsImplicitlyDeclared);
Assert.Equal(c, getAccessor.ContainingSymbol);
Assert.Equal(c, getAccessor.ContainingType);
Assert.Equal(Accessibility.Public, getAccessor.DeclaredAccessibility);
var setAccessor = x.SetMethod;
Assert.Equal(x, setAccessor.AssociatedSymbol);
Assert.True(setAccessor.IsImplicitlyDeclared);
Assert.Equal(c, setAccessor.ContainingSymbol);
Assert.Equal(c, setAccessor.ContainingType);
Assert.Equal(Accessibility.Public, setAccessor.DeclaredAccessibility);
Assert.True(setAccessor.IsInitOnly);
var y = (SourceOrRecordPropertySymbol)c.GetProperty("y");
var y = (SourcePropertySymbolBase)c.GetProperty("y");
Assert.NotNull(y.GetMethod);
Assert.Equal(MethodKind.PropertyGet, y.GetMethod.MethodKind);
Assert.Equal(SpecialType.System_Int32, y.Type.SpecialType);
Assert.False(y.IsReadOnly);
Assert.False(y.IsWriteOnly);
Assert.False(y.IsImplicitlyDeclared);
Assert.Equal(Accessibility.Public, y.DeclaredAccessibility);
Assert.False(x.IsVirtual);
Assert.False(x.IsStatic);
......@@ -192,14 +197,17 @@ public void GeneratedProperties()
Assert.Equal(y, backing.AssociatedSymbol);
Assert.Equal(c, backing.ContainingSymbol);
Assert.Equal(c, backing.ContainingType);
Assert.True(backing.IsImplicitlyDeclared);
getAccessor = y.GetMethod;
Assert.Equal(y, getAccessor.AssociatedSymbol);
Assert.True(getAccessor.IsImplicitlyDeclared);
Assert.Equal(c, getAccessor.ContainingSymbol);
Assert.Equal(c, getAccessor.ContainingType);
setAccessor = y.SetMethod;
Assert.Equal(y, setAccessor.AssociatedSymbol);
Assert.True(setAccessor.IsImplicitlyDeclared);
Assert.Equal(c, setAccessor.ContainingSymbol);
Assert.Equal(c, setAccessor.ContainingType);
Assert.Equal(Accessibility.Public, setAccessor.DeclaredAccessibility);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册