diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 276a331f9a7b9..b26e85c09bb00 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -3777,9 +3777,8 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression) /// /// /// Null for implicit, - /// BaseConstructorInitializerSyntax.ArgumentList, or - /// ThisConstructorInitializerSyntax.ArgumentList, or - /// SimpleBaseTypeSyntax.ArgumentList for explicit. + /// , or + /// for explicit. /// Constructor containing the initializer. /// Accumulates errors (e.g. unable to find constructor to invoke). /// A bound expression for the constructor initializer call. @@ -3921,9 +3920,8 @@ private BoundExpression BindConstructorInitializerCore( errorLocation = initializerSyntax.ThisOrBaseKeyword.GetLocation(); break; - case SimpleBaseTypeSyntax baseWithArguments: - Debug.Assert(baseWithArguments.Parent?.Parent is RecordDeclarationSyntax recordDecl && recordDecl.BaseList.Types.FirstOrDefault() == baseWithArguments); - nonNullSyntax = initializerArgumentListOpt; + case PrimaryConstructorBaseTypeSyntax baseWithArguments: + nonNullSyntax = baseWithArguments; errorLocation = initializerArgumentListOpt.GetLocation(); break; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index be2802ac4751e..ea2cf793cc199 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -3322,7 +3322,7 @@ private BoundNode BindRecordConstructorBody(RecordDeclarationSyntax recordDecl, Debug.Assert(bodyBinder != null); BoundExpressionStatement initializer = null; - if (recordDecl.BaseWithArguments is SimpleBaseTypeSyntax baseWithArguments) + if (recordDecl.PrimaryConstructorBaseType is PrimaryConstructorBaseTypeSyntax baseWithArguments) { initializer = bodyBinder.BindConstructorInitializer(baseWithArguments, diagnostics); } @@ -3334,10 +3334,8 @@ private BoundNode BindRecordConstructorBody(RecordDeclarationSyntax recordDecl, expressionBody: null); } - internal BoundExpressionStatement BindConstructorInitializer(SimpleBaseTypeSyntax initializer, DiagnosticBag diagnostics) + internal virtual BoundExpressionStatement BindConstructorInitializer(PrimaryConstructorBaseTypeSyntax initializer, DiagnosticBag diagnostics) { - Debug.Assert(initializer.Parent?.Parent is RecordDeclarationSyntax recordDecl && recordDecl.ParameterList is object && recordDecl.BaseWithArguments == initializer); - BoundExpression initializerInvocation = GetBinder(initializer).BindConstructorInitializer(initializer.ArgumentList, (MethodSymbol)this.ContainingMember(), diagnostics); var constructorInitializer = new BoundExpressionStatement(initializer, initializerInvocation); Debug.Assert(initializerInvocation.HasAnyErrors || constructorInitializer.IsConstructorInitializer(), "Please keep this bound node in sync with BoundNodeExtensions.IsConstructorInitializer."); diff --git a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs index 48bd938480ade..a2a2eb2767d3b 100644 --- a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs @@ -49,7 +49,7 @@ protected void FindExpressionVariables( case SyntaxKind.GotoCaseStatement: break; case SyntaxKind.ArgumentList: - Debug.Assert(node.Parent is ConstructorInitializerSyntax); + Debug.Assert(node.Parent is ConstructorInitializerSyntax || node.Parent is PrimaryConstructorBaseTypeSyntax); break; case SyntaxKind.RecordDeclaration: Debug.Assert(((RecordDeclarationSyntax)node).ParameterList is object); @@ -397,7 +397,7 @@ public override void VisitRecordDeclaration(RecordDeclarationSyntax node) { Debug.Assert(node.ParameterList is object); - if (node.BaseWithArguments is SimpleBaseTypeSyntax baseWithArguments) + if (node.PrimaryConstructorBaseType is PrimaryConstructorBaseTypeSyntax baseWithArguments) { VisitNodeToBind(baseWithArguments); } diff --git a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index ef27e8dcdd1cf..7a025be2810c6 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -162,13 +162,14 @@ public override void VisitRecordDeclaration(RecordDeclarationSyntax node) Binder enclosing = new ExpressionVariableBinder(node, _enclosing); AddToMap(node, enclosing); + Visit(node.PrimaryConstructorBaseType, enclosing); + } - if (node.BaseWithArguments is SimpleBaseTypeSyntax baseWithArguments) - { - enclosing = enclosing.WithAdditionalFlags(BinderFlags.ConstructorInitializer); - AddToMap(baseWithArguments, enclosing); - Visit(baseWithArguments.ArgumentList, enclosing); - } + public override void VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) + { + Binder enclosing = _enclosing.WithAdditionalFlags(BinderFlags.ConstructorInitializer); + AddToMap(node, enclosing); + VisitConstructorInitializerArgumentList(node, node.ArgumentList, enclosing); } public override void VisitDestructorDeclaration(DestructorDeclarationSyntax node) @@ -317,16 +318,20 @@ public override void VisitConstructorInitializer(ConstructorInitializerSyntax no { var binder = _enclosing.WithAdditionalFlags(BinderFlags.ConstructorInitializer); AddToMap(node, binder); + VisitConstructorInitializerArgumentList(node, node.ArgumentList, binder); + } - if (node.ArgumentList != null) + private void VisitConstructorInitializerArgumentList(CSharpSyntaxNode node, ArgumentListSyntax argumentList, Binder binder) + { + if (argumentList != null) { if (_root == node) { - binder = new ExpressionVariableBinder(node.ArgumentList, binder); - AddToMap(node.ArgumentList, binder); + binder = new ExpressionVariableBinder(argumentList, binder); + AddToMap(argumentList, binder); } - Visit(node.ArgumentList, binder); + Visit(argumentList, binder); } } diff --git a/src/Compilers/CSharp/Portable/CSharpExtensions.cs b/src/Compilers/CSharp/Portable/CSharpExtensions.cs index 1875ac2f36bf3..8e7998236412d 100644 --- a/src/Compilers/CSharp/Portable/CSharpExtensions.cs +++ b/src/Compilers/CSharp/Portable/CSharpExtensions.cs @@ -537,6 +537,22 @@ public static Conversion ClassifyConversion(this Compilation? compilation, IType } } + /// + /// Returns what symbol(s), if any, the given constructor initializer syntax bound to in the program. + /// + public static SymbolInfo GetSymbolInfo(this SemanticModel? semanticModel, PrimaryConstructorBaseTypeSyntax constructorInitializer, CancellationToken cancellationToken = default(CancellationToken)) + { + var csmodel = semanticModel as CSharpSemanticModel; + if (csmodel != null) + { + return csmodel.GetSymbolInfo(constructorInitializer, cancellationToken); + } + else + { + return SymbolInfo.None; + } + } + /// /// Returns what symbol(s), if any, the given attribute syntax bound to in the program. /// @@ -643,6 +659,27 @@ public static SymbolInfo GetSpeculativeSymbolInfo(this SemanticModel? semanticMo } } + /// + /// Bind the constructor initializer in the context of the specified location and get semantic information + /// about symbols. This method is used to get semantic information about a constructor + /// initializer that did not actually appear in the source code. + /// + /// NOTE: This will only work in locations where there is already a constructor initializer. + /// . + /// + public static SymbolInfo GetSpeculativeSymbolInfo(this SemanticModel? semanticModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer) + { + var csmodel = semanticModel as CSharpSemanticModel; + if (csmodel != null) + { + return csmodel.GetSpeculativeSymbolInfo(position, constructorInitializer); + } + else + { + return SymbolInfo.None; + } + } + /// /// Gets type information about a constructor initializer. /// @@ -1178,6 +1215,27 @@ public static bool TryGetSpeculativeSemanticModel([NotNullWhen(true)] this Seman } } + /// + /// Get a SemanticModel object that is associated with a constructor initializer that did not appear in + /// this source code. This can be used to get detailed semantic information about sub-parts + /// of a constructor initializer that did not appear in source code. + /// + /// NOTE: This will only work in locations where there is already a constructor initializer. + /// + public static bool TryGetSpeculativeSemanticModel([NotNullWhen(true)] this SemanticModel? semanticModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, [NotNullWhen(true)] out SemanticModel? speculativeModel) + { + var csmodel = semanticModel as CSharpSemanticModel; + if (csmodel != null) + { + return csmodel.TryGetSpeculativeSemanticModel(position, constructorInitializer, out speculativeModel); + } + else + { + speculativeModel = null; + return false; + } + } + /// /// Get a SemanticModel object that is associated with an attribute that did not appear in /// this source code. This can be used to get detailed semantic information about sub-parts diff --git a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs index cd1a135d60701..c5a400824172a 100644 --- a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs @@ -118,6 +118,12 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return false; } + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + { + speculativeModel = null; + return false; + } + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel) { speculativeModel = null; diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index 41f8b3b4f4eb5..07fb552aeeb41 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs @@ -120,6 +120,7 @@ internal static bool CanGetSemanticInfo(CSharpSyntaxNode node, bool allowNamedAr return (node is ExpressionSyntax && (isSpeculative || allowNamedArgumentName || !SyntaxFacts.IsNamedArgumentName(node))) || (node is ConstructorInitializerSyntax) || + (node is PrimaryConstructorBaseTypeSyntax) || (node is AttributeSyntax) || (node is CrefSyntax); } @@ -636,7 +637,6 @@ private static SymbolInfo GetSymbolInfoFromSymbolOrNone(ITypeSymbol type) return SymbolInfo.None; } - /// /// Returns what symbol(s), if any, the given constructor initializer syntax bound to in the program. /// @@ -651,6 +651,20 @@ private static SymbolInfo GetSymbolInfoFromSymbolOrNone(ITypeSymbol type) : SymbolInfo.None; } + /// + /// Returns what symbol(s), if any, the given constructor initializer syntax bound to in the program. + /// + /// The syntax node to get semantic information for. + /// The cancellation token. + public SymbolInfo GetSymbolInfo(PrimaryConstructorBaseTypeSyntax constructorInitializer, CancellationToken cancellationToken = default(CancellationToken)) + { + CheckSyntaxNode(constructorInitializer); + + return CanGetSemanticInfo(constructorInitializer) + ? GetSymbolInfoWorker(constructorInitializer, SymbolInfoOptions.DefaultOptions, cancellationToken) + : SymbolInfo.None; + } + /// /// Returns what symbol(s), if any, the given attribute syntax bound to in the program. /// @@ -798,7 +812,82 @@ public SymbolInfo GetSpeculativeSymbolInfo(int position, ConstructorInitializerS binder = new ExecutableCodeBinder(constructorInitializer, binder.ContainingMemberOrLambda, binder); BoundExpressionStatement bnode = binder.BindConstructorInitializer(constructorInitializer, diagnostics); - var binfo = memberModel.GetSymbolInfoForNode(SymbolInfoOptions.DefaultOptions, bnode.Expression, bnode.Expression, boundNodeForSyntacticParent: null, binderOpt: binder); + var binfo = GetSymbolInfoFromBoundConstructorInitializer(memberModel, binder, bnode); + diagnostics.Free(); + return binfo; + } + else + { + return SymbolInfo.None; + } + } + + private static SymbolInfo GetSymbolInfoFromBoundConstructorInitializer(MemberSemanticModel memberModel, Binder binder, BoundExpressionStatement bnode) + { + BoundExpression expression = bnode.Expression; + + while (expression is BoundSequence sequence) + { + expression = sequence.Value; + } + + return memberModel.GetSymbolInfoForNode(SymbolInfoOptions.DefaultOptions, expression, expression, boundNodeForSyntacticParent: null, binderOpt: binder); + } + + /// + /// Bind the constructor initializer in the context of the specified location and get semantic information + /// about symbols. This method is used to get semantic information about a constructor + /// initializer that did not actually appear in the source code. + /// + /// NOTE: This will only work in locations where there is already a constructor initializer. + /// + /// A character position used to identify a declaration scope and accessibility. This + /// character position must be within the span of an existing constructor initializer. + /// + /// A syntax node that represents a parsed constructor initializer. This syntax node + /// need not and typically does not appear in the source code referred to SemanticModel instance. + /// The semantic information for the topmost node of the constructor initializer. + public SymbolInfo GetSpeculativeSymbolInfo(int position, PrimaryConstructorBaseTypeSyntax constructorInitializer) + { + Debug.Assert(CanGetSemanticInfo(constructorInitializer, isSpeculative: true)); + + position = CheckAndAdjustPosition(position); + + if (constructorInitializer == null) + { + throw new ArgumentNullException(nameof(constructorInitializer)); + } + + // NOTE: since we're going to be depending on a MemberModel to do the binding for us, + // we need to find a constructor initializer in the tree of this semantic model. + // NOTE: This approach will not allow speculative binding of a constructor initializer + // on a constructor that didn't formerly have one. + // TODO: Should we support positions that are not in existing constructor initializers? + // If so, we will need to build up the context that would otherwise be built up by + // InitializerMemberModel. + var existingConstructorInitializer = this.Root.FindToken(position).Parent.AncestorsAndSelf().OfType().FirstOrDefault(); + + if (existingConstructorInitializer == null) + { + return SymbolInfo.None; + } + + MemberSemanticModel memberModel = GetMemberModel(existingConstructorInitializer); + + if (memberModel == null) + { + return SymbolInfo.None; + } + + var argumentList = existingConstructorInitializer.ArgumentList; + var binder = memberModel.GetEnclosingBinder(LookupPosition.IsBetweenTokens(position, argumentList.OpenParenToken, argumentList.CloseParenToken) ? position : argumentList.OpenParenToken.SpanStart); + if (binder != null) + { + var diagnostics = DiagnosticBag.GetInstance(); + binder = new ExecutableCodeBinder(constructorInitializer, binder.ContainingMemberOrLambda, binder); + + BoundExpressionStatement bnode = binder.BindConstructorInitializer(constructorInitializer, diagnostics); + SymbolInfo binfo = GetSymbolInfoFromBoundConstructorInitializer(memberModel, binder, bnode); diagnostics.Free(); return binfo; } @@ -1014,7 +1103,7 @@ public Conversion GetSpeculativeConversion(int position, ExpressionSyntax expres } /// - /// Gets a list of method or indexed property symbols for a syntax node. + /// Gets a list of method symbols for a syntax node. /// /// The syntax node to get semantic information for. /// The cancellation token. @@ -2514,6 +2603,33 @@ public bool TryGetSpeculativeSemanticModel(int position, ConstructorInitializerS internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel speculativeModel); + /// + /// Get a SemanticModel object that is associated with a constructor initializer that did not appear in + /// this source code. This can be used to get detailed semantic information about sub-parts + /// of a constructor initializer that did not appear in source code. + /// + /// NOTE: This will only work in locations where there is already a constructor initializer. + /// + /// A character position used to identify a declaration scope and accessibility. This + /// character position must be within the span of an existing constructor initializer. + /// + /// A syntax node that represents a parsed constructor initializer. + /// This node should not be present in the syntax tree associated with this object. + /// A SemanticModel object that can be used to inquire about the semantic + /// information associated with syntax nodes within . + /// Flag indicating whether a speculative semantic model was created. + /// Throws this exception if the node is contained any SyntaxTree in the current Compilation. + /// Throws this exception if is null. + /// Throws this exception if this model is a speculative semantic model, i.e. is true. + /// Chaining of speculative semantic model is not supported. + public bool TryGetSpeculativeSemanticModel(int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + { + CheckModelAndSyntaxNodeToSpeculate(constructorInitializer); + return TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, constructorInitializer, out speculativeModel); + } + + internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel); + /// /// Get a SemanticModel object that is associated with a cref that did not appear in /// this source code. This can be used to get detailed semantic information about sub-parts @@ -4753,6 +4869,8 @@ private SymbolInfo GetSymbolInfoFromNode(SyntaxNode node, CancellationToken canc return this.GetSymbolInfo(expression, cancellationToken); case ConstructorInitializerSyntax initializer: return this.GetSymbolInfo(initializer, cancellationToken); + case PrimaryConstructorBaseTypeSyntax initializer: + return this.GetSymbolInfo(initializer, cancellationToken); case AttributeSyntax attribute: return this.GetSymbolInfo(attribute, cancellationToken); case CrefSyntax cref: @@ -4820,6 +4938,8 @@ protected sealed override SymbolInfo GetSpeculativeSymbolInfoCore(int position, return GetSpeculativeSymbolInfo(position, expression, bindingOption); case ConstructorInitializerSyntax initializer: return GetSpeculativeSymbolInfo(position, initializer); + case PrimaryConstructorBaseTypeSyntax initializer: + return GetSpeculativeSymbolInfo(position, initializer); case AttributeSyntax attribute: return GetSpeculativeSymbolInfo(position, attribute); case CrefSyntax cref: diff --git a/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs index bcaca17ced874..7ae4615fa0954 100644 --- a/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs @@ -30,7 +30,7 @@ private InitializerSemanticModel(CSharpSyntaxNode syntax, int speculatedPosition = 0) : base(syntax, symbol, rootBinder, containingSemanticModelOpt, parentSemanticModelOpt, snapshotManagerOpt: null, parentRemappedSymbolsOpt, speculatedPosition) { - Debug.Assert(!(syntax is ConstructorInitializerSyntax)); + Debug.Assert(!(syntax is ConstructorInitializerSyntax || syntax is PrimaryConstructorBaseTypeSyntax)); } /// @@ -104,11 +104,6 @@ internal override BoundNode GetBoundRoot() rootSyntax = ((EnumMemberDeclarationSyntax)rootSyntax).EqualsValue.Value; break; - case SyntaxKind.BaseConstructorInitializer: - case SyntaxKind.ThisConstructorInitializer: - case SyntaxKind.ArgumentList: - break; - case SyntaxKind.PropertyDeclaration: rootSyntax = ((PropertyDeclarationSyntax)rootSyntax).Initializer.Value; break; @@ -207,11 +202,6 @@ private bool IsBindableInitializer(CSharpSyntaxNode node) return this.Root == node || /*enum or parameter initializer*/ this.Root == node.Parent /*field initializer*/; - case SyntaxKind.BaseConstructorInitializer: - case SyntaxKind.ThisConstructorInitializer: - case SyntaxKind.ArgumentList: - return this.Root == node; - default: return false; } @@ -237,6 +227,12 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return false; } + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + { + speculativeModel = null; + return false; + } + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out SemanticModel speculativeModel) { speculativeModel = null; diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.SpeculativeMemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.SpeculativeMemberSemanticModel.cs index 197ac790a5366..9b41ade76912c 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.SpeculativeMemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.SpeculativeMemberSemanticModel.cs @@ -49,6 +49,11 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode throw ExceptionUtilities.Unreachable; } + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + { + throw ExceptionUtilities.Unreachable; + } + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel) { throw ExceptionUtilities.Unreachable; diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index 6a2d25d132d91..233dc45f1f834 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -317,7 +317,7 @@ private static Binder GetEnclosingBinderInternalWithinRoot(SyntaxNode node, int { binder = rootBinder.GetBinder(current); } - else if (kind == SyntaxKind.ThisConstructorInitializer || kind == SyntaxKind.BaseConstructorInitializer || kind == SyntaxKind.SimpleBaseType) + else if (kind == SyntaxKind.ThisConstructorInitializer || kind == SyntaxKind.BaseConstructorInitializer || kind == SyntaxKind.PrimaryConstructorBaseType) { binder = rootBinder.GetBinder(current); } @@ -1549,6 +1549,7 @@ private CSharpSyntaxNode GetBindingRoot(CSharpSyntaxNode node) { case SyntaxKind.ThisConstructorInitializer: case SyntaxKind.BaseConstructorInitializer: + case SyntaxKind.PrimaryConstructorBaseType: return current; case SyntaxKind.ArrowExpressionClause: // If this is an arrow expression on a local function statement, then our bindable root is actually our parent syntax as it's @@ -2207,6 +2208,7 @@ internal protected virtual CSharpSyntaxNode GetBindableSyntaxNode(CSharpSyntaxNo !(node is JoinIntoClauseSyntax) && !(node is QueryContinuationSyntax) && !(node is ConstructorInitializerSyntax) && + !(node is PrimaryConstructorBaseTypeSyntax) && !(node is ArrowExpressionClauseSyntax) && !(node is PatternSyntax)) { @@ -2433,6 +2435,11 @@ internal override BoundExpressionStatement BindConstructorInitializer(Constructo return (BoundExpressionStatement)TryGetBoundNodeFromMap(node) ?? base.BindConstructorInitializer(node, diagnostics); } + internal override BoundExpressionStatement BindConstructorInitializer(PrimaryConstructorBaseTypeSyntax node, DiagnosticBag diagnostics) + { + return (BoundExpressionStatement)TryGetBoundNodeFromMap(node) ?? base.BindConstructorInitializer(node, diagnostics); + } + internal override BoundBlock BindExpressionBodyAsBlock(ArrowExpressionClauseSyntax node, DiagnosticBag diagnostics) { BoundBlock block = (BoundBlock)TryGetBoundNodeFromMap(node); diff --git a/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs index 7a2090bd1e8d8..9a43b48c9a43d 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -85,6 +86,9 @@ internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, Diagnosti case SyntaxKind.ThisConstructorInitializer: return binder.BindConstructorInitializer((ConstructorInitializerSyntax)node, diagnostics); + case SyntaxKind.PrimaryConstructorBaseType: + return binder.BindConstructorInitializer((PrimaryConstructorBaseTypeSyntax)node, diagnostics); + case SyntaxKind.MethodDeclaration: case SyntaxKind.ConversionOperatorDeclaration: case SyntaxKind.OperatorDeclaration: @@ -149,6 +153,19 @@ internal static MethodBodySemanticModel CreateSpeculative(SyntaxTreeSemanticMode return new MethodBodySemanticModel(owner, rootBinder, syntax, parentSemanticModelOpt: parentSemanticModel, speculatedPosition: position); } + /// + /// Creates a speculative SemanticModel for a constructor initializer that did not appear in the original source code. + /// + internal static MethodBodySemanticModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, MethodSymbol owner, PrimaryConstructorBaseTypeSyntax syntax, Binder rootBinder, int position) + { + Debug.Assert(parentSemanticModel != null); + Debug.Assert(syntax != null); + Debug.Assert(rootBinder != null); + Debug.Assert(rootBinder.IsSemanticModelBinder); + + return new MethodBodySemanticModel(owner, rootBinder, syntax, parentSemanticModelOpt: parentSemanticModel, speculatedPosition: position); + } + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out SemanticModel speculativeModel) { // CONSIDER: Do we want to ensure that speculated method and the original method have identical signatures? @@ -231,12 +248,12 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel speculativeModel) { - if ((MemberSymbol as MethodSymbol)?.MethodKind == MethodKind.Constructor) + if (MemberSymbol is MethodSymbol methodSymbol && methodSymbol.MethodKind == MethodKind.Constructor && + Root.FindToken(position).Parent?.AncestorsAndSelf().OfType().FirstOrDefault()?.Parent == Root) { var binder = this.GetEnclosingBinder(position); if (binder != null) { - var methodSymbol = (MethodSymbol)this.MemberSymbol; binder = new WithNullableContextBinder(SyntaxTree, position, binder); binder = new ExecutableCodeBinder(constructorInitializer, methodSymbol, binder); speculativeModel = CreateSpeculative(parentModel, methodSymbol, constructorInitializer, binder, position); @@ -248,6 +265,25 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return false; } + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + { + if (MemberSymbol is SynthesizedRecordConstructor primaryCtor && + Root.FindToken(position).Parent?.AncestorsAndSelf().OfType().FirstOrDefault() == primaryCtor.GetSyntax().PrimaryConstructorBaseType) + { + var binder = this.GetEnclosingBinder(position); + if (binder != null) + { + binder = new WithNullableContextBinder(SyntaxTree, position, binder); + binder = new ExecutableCodeBinder(constructorInitializer, primaryCtor, binder); + speculativeModel = CreateSpeculative(parentModel, primaryCtor, constructorInitializer, binder, position); + return true; + } + } + + speculativeModel = null; + return false; + } + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel) { speculativeModel = null; diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs index e31435850de7a..1c5c44a5064d7 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs @@ -711,10 +711,34 @@ internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSeman { position = CheckAndAdjustPosition(position); - var model = this.GetMemberModel(position); - if (model != null) + var existingConstructorInitializer = this.Root.FindToken(position).Parent.AncestorsAndSelf().OfType().FirstOrDefault(); + + if (existingConstructorInitializer != null) + { + var model = this.GetMemberModel(position); + if (model != null) + { + return model.TryGetSpeculativeSemanticModelCore(parentModel, position, constructorInitializer, out speculativeModel); + } + } + + speculativeModel = null; + return false; + } + + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + { + position = CheckAndAdjustPosition(position); + + var existingConstructorInitializer = this.Root.FindToken(position).Parent.AncestorsAndSelf().OfType().FirstOrDefault(); + + if (existingConstructorInitializer != null) { - return model.TryGetSpeculativeSemanticModelCore(parentModel, position, constructorInitializer, out speculativeModel); + var model = this.GetMemberModel(existingConstructorInitializer); + if (model != null) + { + return model.TryGetSpeculativeSemanticModelCore(parentModel, position, constructorInitializer, out speculativeModel); + } } speculativeModel = null; @@ -784,7 +808,7 @@ private MemberSemanticModel GetMemberModel(int position) } else { - var argumentList = recordDecl.BaseWithArguments?.ArgumentList; + var argumentList = recordDecl.PrimaryConstructorBaseType?.ArgumentList; outsideMemberDecl = argumentList is null || !LookupPosition.IsBetweenTokens(position, argumentList.OpenParenToken, argumentList.CloseParenToken); } } @@ -846,7 +870,9 @@ internal override MemberSemanticModel GetMemberModel(SyntaxNode node) case SyntaxKind.RecordDeclaration: { var recordDecl = (RecordDeclarationSyntax)memberDecl; - return recordDecl.ParameterList is object && recordDecl.BaseWithArguments?.ArgumentList.FullSpan.Contains(span) == true ? GetOrAddModel(memberDecl) : null; + return recordDecl.ParameterList is object && + recordDecl.PrimaryConstructorBaseType is PrimaryConstructorBaseTypeSyntax baseWithArguments && + (node == baseWithArguments || baseWithArguments.ArgumentList.FullSpan.Contains(span)) ? GetOrAddModel(memberDecl) : null; } case SyntaxKind.DestructorDeclaration: diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 index 9791532660a28..b522789a8b835 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 +++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 @@ -272,11 +272,16 @@ base_list ; base_type - : simple_base_type + : primary_constructor_base_type + | simple_base_type + ; + +primary_constructor_base_type + : type argument_list ; simple_base_type - : type argument_list? + : type ; enum_member_declaration diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs index 7c7c3d2403d0e..05ef43a82fc30 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs @@ -22279,50 +22279,124 @@ protected BaseTypeSyntax(ObjectReader reader) internal sealed partial class SimpleBaseTypeSyntax : BaseTypeSyntax { internal readonly TypeSyntax type; - internal readonly ArgumentListSyntax? argumentList; - internal SimpleBaseTypeSyntax(SyntaxKind kind, TypeSyntax type, ArgumentListSyntax? argumentList, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + internal SimpleBaseTypeSyntax(SyntaxKind kind, TypeSyntax type, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) : base(kind, diagnostics, annotations) { - this.SlotCount = 2; + this.SlotCount = 1; this.AdjustFlagsAndWidth(type); this.type = type; - if (argumentList != null) + } + + internal SimpleBaseTypeSyntax(SyntaxKind kind, TypeSyntax type, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 1; + this.AdjustFlagsAndWidth(type); + this.type = type; + } + + internal SimpleBaseTypeSyntax(SyntaxKind kind, TypeSyntax type) + : base(kind) + { + this.SlotCount = 1; + this.AdjustFlagsAndWidth(type); + this.type = type; + } + + public override TypeSyntax Type => this.type; + + internal override GreenNode? GetSlot(int index) + => index == 0 ? this.type : null; + + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.SimpleBaseTypeSyntax(this, parent, position); + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitSimpleBaseType(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitSimpleBaseType(this); + + public SimpleBaseTypeSyntax Update(TypeSyntax type) + { + if (type != this.Type) { - this.AdjustFlagsAndWidth(argumentList); - this.argumentList = argumentList; + var newNode = SyntaxFactory.SimpleBaseType(type); + var diags = GetDiagnostics(); + if (diags?.Length > 0) + newNode = newNode.WithDiagnosticsGreen(diags); + var annotations = GetAnnotations(); + if (annotations?.Length > 0) + newNode = newNode.WithAnnotationsGreen(annotations); + return newNode; } + + return this; + } + + internal override GreenNode SetDiagnostics(DiagnosticInfo[]? diagnostics) + => new SimpleBaseTypeSyntax(this.Kind, this.type, diagnostics, GetAnnotations()); + + internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) + => new SimpleBaseTypeSyntax(this.Kind, this.type, GetDiagnostics(), annotations); + + internal SimpleBaseTypeSyntax(ObjectReader reader) + : base(reader) + { + this.SlotCount = 1; + var type = (TypeSyntax)reader.ReadValue(); + AdjustFlagsAndWidth(type); + this.type = type; + } + + internal override void WriteTo(ObjectWriter writer) + { + base.WriteTo(writer); + writer.WriteValue(this.type); + } + + static SimpleBaseTypeSyntax() + { + ObjectBinder.RegisterTypeReader(typeof(SimpleBaseTypeSyntax), r => new SimpleBaseTypeSyntax(r)); + } + } + + internal sealed partial class PrimaryConstructorBaseTypeSyntax : BaseTypeSyntax + { + internal readonly TypeSyntax type; + internal readonly ArgumentListSyntax argumentList; + + internal PrimaryConstructorBaseTypeSyntax(SyntaxKind kind, TypeSyntax type, ArgumentListSyntax argumentList, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 2; + this.AdjustFlagsAndWidth(type); + this.type = type; + this.AdjustFlagsAndWidth(argumentList); + this.argumentList = argumentList; } - internal SimpleBaseTypeSyntax(SyntaxKind kind, TypeSyntax type, ArgumentListSyntax? argumentList, SyntaxFactoryContext context) + internal PrimaryConstructorBaseTypeSyntax(SyntaxKind kind, TypeSyntax type, ArgumentListSyntax argumentList, SyntaxFactoryContext context) : base(kind) { this.SetFactoryContext(context); this.SlotCount = 2; this.AdjustFlagsAndWidth(type); this.type = type; - if (argumentList != null) - { - this.AdjustFlagsAndWidth(argumentList); - this.argumentList = argumentList; - } + this.AdjustFlagsAndWidth(argumentList); + this.argumentList = argumentList; } - internal SimpleBaseTypeSyntax(SyntaxKind kind, TypeSyntax type, ArgumentListSyntax? argumentList) + internal PrimaryConstructorBaseTypeSyntax(SyntaxKind kind, TypeSyntax type, ArgumentListSyntax argumentList) : base(kind) { this.SlotCount = 2; this.AdjustFlagsAndWidth(type); this.type = type; - if (argumentList != null) - { - this.AdjustFlagsAndWidth(argumentList); - this.argumentList = argumentList; - } + this.AdjustFlagsAndWidth(argumentList); + this.argumentList = argumentList; } public override TypeSyntax Type => this.type; - public ArgumentListSyntax? ArgumentList => this.argumentList; + public ArgumentListSyntax ArgumentList => this.argumentList; internal override GreenNode? GetSlot(int index) => index switch @@ -22332,16 +22406,16 @@ internal SimpleBaseTypeSyntax(SyntaxKind kind, TypeSyntax type, ArgumentListSynt _ => null, }; - internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.SimpleBaseTypeSyntax(this, parent, position); + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.PrimaryConstructorBaseTypeSyntax(this, parent, position); - public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitSimpleBaseType(this); - public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitSimpleBaseType(this); + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitPrimaryConstructorBaseType(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitPrimaryConstructorBaseType(this); - public SimpleBaseTypeSyntax Update(TypeSyntax type, ArgumentListSyntax argumentList) + public PrimaryConstructorBaseTypeSyntax Update(TypeSyntax type, ArgumentListSyntax argumentList) { if (type != this.Type || argumentList != this.ArgumentList) { - var newNode = SyntaxFactory.SimpleBaseType(type, argumentList); + var newNode = SyntaxFactory.PrimaryConstructorBaseType(type, argumentList); var diags = GetDiagnostics(); if (diags?.Length > 0) newNode = newNode.WithDiagnosticsGreen(diags); @@ -22355,24 +22429,21 @@ public SimpleBaseTypeSyntax Update(TypeSyntax type, ArgumentListSyntax argumentL } internal override GreenNode SetDiagnostics(DiagnosticInfo[]? diagnostics) - => new SimpleBaseTypeSyntax(this.Kind, this.type, this.argumentList, diagnostics, GetAnnotations()); + => new PrimaryConstructorBaseTypeSyntax(this.Kind, this.type, this.argumentList, diagnostics, GetAnnotations()); internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) - => new SimpleBaseTypeSyntax(this.Kind, this.type, this.argumentList, GetDiagnostics(), annotations); + => new PrimaryConstructorBaseTypeSyntax(this.Kind, this.type, this.argumentList, GetDiagnostics(), annotations); - internal SimpleBaseTypeSyntax(ObjectReader reader) + internal PrimaryConstructorBaseTypeSyntax(ObjectReader reader) : base(reader) { this.SlotCount = 2; var type = (TypeSyntax)reader.ReadValue(); AdjustFlagsAndWidth(type); this.type = type; - var argumentList = (ArgumentListSyntax?)reader.ReadValue(); - if (argumentList != null) - { - AdjustFlagsAndWidth(argumentList); - this.argumentList = argumentList; - } + var argumentList = (ArgumentListSyntax)reader.ReadValue(); + AdjustFlagsAndWidth(argumentList); + this.argumentList = argumentList; } internal override void WriteTo(ObjectWriter writer) @@ -22382,9 +22453,9 @@ internal override void WriteTo(ObjectWriter writer) writer.WriteValue(this.argumentList); } - static SimpleBaseTypeSyntax() + static PrimaryConstructorBaseTypeSyntax() { - ObjectBinder.RegisterTypeReader(typeof(SimpleBaseTypeSyntax), r => new SimpleBaseTypeSyntax(r)); + ObjectBinder.RegisterTypeReader(typeof(PrimaryConstructorBaseTypeSyntax), r => new PrimaryConstructorBaseTypeSyntax(r)); } } @@ -32376,6 +32447,7 @@ internal partial class CSharpSyntaxVisitor public virtual TResult VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); public virtual TResult VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); public virtual TResult VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node); + public virtual TResult VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node); public virtual TResult VisitTypeParameterConstraintClause(TypeParameterConstraintClauseSyntax node) => this.DefaultVisit(node); public virtual TResult VisitConstructorConstraint(ConstructorConstraintSyntax node) => this.DefaultVisit(node); public virtual TResult VisitClassOrStructConstraint(ClassOrStructConstraintSyntax node) => this.DefaultVisit(node); @@ -32604,6 +32676,7 @@ internal partial class CSharpSyntaxVisitor public virtual void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); public virtual void VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); public virtual void VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node); + public virtual void VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node); public virtual void VisitTypeParameterConstraintClause(TypeParameterConstraintClauseSyntax node) => this.DefaultVisit(node); public virtual void VisitConstructorConstraint(ConstructorConstraintSyntax node) => this.DefaultVisit(node); public virtual void VisitClassOrStructConstraint(ClassOrStructConstraintSyntax node) => this.DefaultVisit(node); @@ -33148,6 +33221,9 @@ public override CSharpSyntaxNode VisitBaseList(BaseListSyntax node) => node.Update((SyntaxToken)Visit(node.ColonToken), VisitList(node.Types)); public override CSharpSyntaxNode VisitSimpleBaseType(SimpleBaseTypeSyntax node) + => node.Update((TypeSyntax)Visit(node.Type)); + + public override CSharpSyntaxNode VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => node.Update((TypeSyntax)Visit(node.Type), (ArgumentListSyntax)Visit(node.ArgumentList)); public override CSharpSyntaxNode VisitTypeParameterConstraintClause(TypeParameterConstraintClauseSyntax node) @@ -36736,17 +36812,37 @@ public BaseListSyntax BaseList(SyntaxToken colonToken, Microsoft.CodeAnalysis.Sy return result; } - public SimpleBaseTypeSyntax SimpleBaseType(TypeSyntax type, ArgumentListSyntax? argumentList) + public SimpleBaseTypeSyntax SimpleBaseType(TypeSyntax type) { #if DEBUG if (type == null) throw new ArgumentNullException(nameof(type)); #endif int hash; - var cached = CSharpSyntaxNodeCache.TryGetNode((int)SyntaxKind.SimpleBaseType, type, argumentList, this.context, out hash); + var cached = CSharpSyntaxNodeCache.TryGetNode((int)SyntaxKind.SimpleBaseType, type, this.context, out hash); if (cached != null) return (SimpleBaseTypeSyntax)cached; - var result = new SimpleBaseTypeSyntax(SyntaxKind.SimpleBaseType, type, argumentList, this.context); + var result = new SimpleBaseTypeSyntax(SyntaxKind.SimpleBaseType, type, this.context); + if (hash >= 0) + { + SyntaxNodeCache.AddNode(result, hash); + } + + return result; + } + + public PrimaryConstructorBaseTypeSyntax PrimaryConstructorBaseType(TypeSyntax type, ArgumentListSyntax argumentList) + { +#if DEBUG + if (type == null) throw new ArgumentNullException(nameof(type)); + if (argumentList == null) throw new ArgumentNullException(nameof(argumentList)); +#endif + + int hash; + var cached = CSharpSyntaxNodeCache.TryGetNode((int)SyntaxKind.PrimaryConstructorBaseType, type, argumentList, this.context, out hash); + if (cached != null) return (PrimaryConstructorBaseTypeSyntax)cached; + + var result = new PrimaryConstructorBaseTypeSyntax(SyntaxKind.PrimaryConstructorBaseType, type, argumentList, this.context); if (hash >= 0) { SyntaxNodeCache.AddNode(result, hash); @@ -41486,17 +41582,37 @@ public static BaseListSyntax BaseList(SyntaxToken colonToken, Microsoft.CodeAnal return result; } - public static SimpleBaseTypeSyntax SimpleBaseType(TypeSyntax type, ArgumentListSyntax? argumentList) + public static SimpleBaseTypeSyntax SimpleBaseType(TypeSyntax type) { #if DEBUG if (type == null) throw new ArgumentNullException(nameof(type)); #endif int hash; - var cached = SyntaxNodeCache.TryGetNode((int)SyntaxKind.SimpleBaseType, type, argumentList, out hash); + var cached = SyntaxNodeCache.TryGetNode((int)SyntaxKind.SimpleBaseType, type, out hash); if (cached != null) return (SimpleBaseTypeSyntax)cached; - var result = new SimpleBaseTypeSyntax(SyntaxKind.SimpleBaseType, type, argumentList); + var result = new SimpleBaseTypeSyntax(SyntaxKind.SimpleBaseType, type); + if (hash >= 0) + { + SyntaxNodeCache.AddNode(result, hash); + } + + return result; + } + + public static PrimaryConstructorBaseTypeSyntax PrimaryConstructorBaseType(TypeSyntax type, ArgumentListSyntax argumentList) + { +#if DEBUG + if (type == null) throw new ArgumentNullException(nameof(type)); + if (argumentList == null) throw new ArgumentNullException(nameof(argumentList)); +#endif + + int hash; + var cached = SyntaxNodeCache.TryGetNode((int)SyntaxKind.PrimaryConstructorBaseType, type, argumentList, out hash); + if (cached != null) return (PrimaryConstructorBaseTypeSyntax)cached; + + var result = new PrimaryConstructorBaseTypeSyntax(SyntaxKind.PrimaryConstructorBaseType, type, argumentList); if (hash >= 0) { SyntaxNodeCache.AddNode(result, hash); @@ -43012,6 +43128,7 @@ internal static IEnumerable GetNodeTypes() typeof(EnumMemberDeclarationSyntax), typeof(BaseListSyntax), typeof(SimpleBaseTypeSyntax), + typeof(PrimaryConstructorBaseTypeSyntax), typeof(TypeParameterConstraintClauseSyntax), typeof(ConstructorConstraintSyntax), typeof(ClassOrStructConstraintSyntax), diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs index 9ab4b6174aa34..2940354e56d5f 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs @@ -651,6 +651,10 @@ public partial class CSharpSyntaxVisitor [return: MaybeNull] public virtual TResult VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a PrimaryConstructorBaseTypeSyntax node. + [return: MaybeNull] + public virtual TResult VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a TypeParameterConstraintClauseSyntax node. [return: MaybeNull] public virtual TResult VisitTypeParameterConstraintClause(TypeParameterConstraintClauseSyntax node) => this.DefaultVisit(node); @@ -1391,6 +1395,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a SimpleBaseTypeSyntax node. public virtual void VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a PrimaryConstructorBaseTypeSyntax node. + public virtual void VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a TypeParameterConstraintClauseSyntax node. public virtual void VisitTypeParameterConstraintClause(TypeParameterConstraintClauseSyntax node) => this.DefaultVisit(node); @@ -2064,7 +2071,10 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor => node.Update(VisitToken(node.ColonToken), VisitList(node.Types)); public override SyntaxNode? VisitSimpleBaseType(SimpleBaseTypeSyntax node) - => node.Update((TypeSyntax?)Visit(node.Type) ?? throw new ArgumentNullException("type"), (ArgumentListSyntax?)Visit(node.ArgumentList)); + => node.Update((TypeSyntax?)Visit(node.Type) ?? throw new ArgumentNullException("type")); + + public override SyntaxNode? VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) + => node.Update((TypeSyntax?)Visit(node.Type) ?? throw new ArgumentNullException("type"), (ArgumentListSyntax?)Visit(node.ArgumentList) ?? throw new ArgumentNullException("argumentList")); public override SyntaxNode? VisitTypeParameterConstraintClause(TypeParameterConstraintClauseSyntax node) => node.Update(VisitToken(node.WhereKeyword), (IdentifierNameSyntax?)Visit(node.Name) ?? throw new ArgumentNullException("name"), VisitToken(node.ColonToken), VisitList(node.Constraints)); @@ -5044,15 +5054,23 @@ public static BaseListSyntax BaseList(SeparatedSyntaxList types => SyntaxFactory.BaseList(SyntaxFactory.Token(SyntaxKind.ColonToken), types); /// Creates a new SimpleBaseTypeSyntax instance. - public static SimpleBaseTypeSyntax SimpleBaseType(TypeSyntax type, ArgumentListSyntax? argumentList) + public static SimpleBaseTypeSyntax SimpleBaseType(TypeSyntax type) { if (type == null) throw new ArgumentNullException(nameof(type)); - return (SimpleBaseTypeSyntax)Syntax.InternalSyntax.SyntaxFactory.SimpleBaseType((Syntax.InternalSyntax.TypeSyntax)type.Green, argumentList == null ? null : (Syntax.InternalSyntax.ArgumentListSyntax)argumentList.Green).CreateRed(); + return (SimpleBaseTypeSyntax)Syntax.InternalSyntax.SyntaxFactory.SimpleBaseType((Syntax.InternalSyntax.TypeSyntax)type.Green).CreateRed(); } - /// Creates a new SimpleBaseTypeSyntax instance. - public static SimpleBaseTypeSyntax SimpleBaseType(TypeSyntax type) - => SyntaxFactory.SimpleBaseType(type, default); + /// Creates a new PrimaryConstructorBaseTypeSyntax instance. + public static PrimaryConstructorBaseTypeSyntax PrimaryConstructorBaseType(TypeSyntax type, ArgumentListSyntax argumentList) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + if (argumentList == null) throw new ArgumentNullException(nameof(argumentList)); + return (PrimaryConstructorBaseTypeSyntax)Syntax.InternalSyntax.SyntaxFactory.PrimaryConstructorBaseType((Syntax.InternalSyntax.TypeSyntax)type.Green, (Syntax.InternalSyntax.ArgumentListSyntax)argumentList.Green).CreateRed(); + } + + /// Creates a new PrimaryConstructorBaseTypeSyntax instance. + public static PrimaryConstructorBaseTypeSyntax PrimaryConstructorBaseType(TypeSyntax type) + => SyntaxFactory.PrimaryConstructorBaseType(type, SyntaxFactory.ArgumentList()); /// Creates a new TypeParameterConstraintClauseSyntax instance. public static TypeParameterConstraintClauseSyntax TypeParameterConstraintClause(SyntaxToken whereKeyword, IdentifierNameSyntax name, SyntaxToken colonToken, SeparatedSyntaxList constraints) diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs index 88d43df3f1f7f..0535a9109294c 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs @@ -9578,7 +9578,6 @@ internal BaseTypeSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? paren public sealed partial class SimpleBaseTypeSyntax : BaseTypeSyntax { private TypeSyntax? type; - private ArgumentListSyntax? argumentList; internal SimpleBaseTypeSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) : base(green, parent, position) @@ -9587,13 +9586,49 @@ internal SimpleBaseTypeSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? public override TypeSyntax Type => GetRedAtZero(ref this.type)!; - public ArgumentListSyntax? ArgumentList => GetRed(ref this.argumentList, 1); + internal override SyntaxNode? GetNodeSlot(int index) => index == 0 ? GetRedAtZero(ref this.type)! : null; + + internal override SyntaxNode? GetCachedSlot(int index) => index == 0 ? this.type : null; + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitSimpleBaseType(this); + [return: MaybeNull] + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitSimpleBaseType(this); + + public SimpleBaseTypeSyntax Update(TypeSyntax type) + { + if (type != this.Type) + { + var newNode = SyntaxFactory.SimpleBaseType(type); + var annotations = GetAnnotations(); + return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; + } + + return this; + } + + internal override BaseTypeSyntax WithTypeCore(TypeSyntax type) => WithType(type); + public new SimpleBaseTypeSyntax WithType(TypeSyntax type) => Update(type); + } + + public sealed partial class PrimaryConstructorBaseTypeSyntax : BaseTypeSyntax + { + private TypeSyntax? type; + private ArgumentListSyntax? argumentList; + + internal PrimaryConstructorBaseTypeSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) + : base(green, parent, position) + { + } + + public override TypeSyntax Type => GetRedAtZero(ref this.type)!; + + public ArgumentListSyntax ArgumentList => GetRed(ref this.argumentList, 1)!; internal override SyntaxNode? GetNodeSlot(int index) => index switch { 0 => GetRedAtZero(ref this.type)!, - 1 => GetRed(ref this.argumentList, 1), + 1 => GetRed(ref this.argumentList, 1)!, _ => null, }; @@ -9605,15 +9640,15 @@ internal SimpleBaseTypeSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? _ => null, }; - public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitSimpleBaseType(this); + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitPrimaryConstructorBaseType(this); [return: MaybeNull] - public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitSimpleBaseType(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitPrimaryConstructorBaseType(this); - public SimpleBaseTypeSyntax Update(TypeSyntax type, ArgumentListSyntax? argumentList) + public PrimaryConstructorBaseTypeSyntax Update(TypeSyntax type, ArgumentListSyntax argumentList) { if (type != this.Type || argumentList != this.ArgumentList) { - var newNode = SyntaxFactory.SimpleBaseType(type, argumentList); + var newNode = SyntaxFactory.PrimaryConstructorBaseType(type, argumentList); var annotations = GetAnnotations(); return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; } @@ -9622,14 +9657,10 @@ public SimpleBaseTypeSyntax Update(TypeSyntax type, ArgumentListSyntax? argument } internal override BaseTypeSyntax WithTypeCore(TypeSyntax type) => WithType(type); - public new SimpleBaseTypeSyntax WithType(TypeSyntax type) => Update(type, this.ArgumentList); - public SimpleBaseTypeSyntax WithArgumentList(ArgumentListSyntax? argumentList) => Update(this.Type, argumentList); + public new PrimaryConstructorBaseTypeSyntax WithType(TypeSyntax type) => Update(type, this.ArgumentList); + public PrimaryConstructorBaseTypeSyntax WithArgumentList(ArgumentListSyntax argumentList) => Update(this.Type, argumentList); - public SimpleBaseTypeSyntax AddArgumentListArguments(params ArgumentSyntax[] items) - { - var argumentList = this.ArgumentList ?? SyntaxFactory.ArgumentList(); - return WithArgumentList(argumentList.WithArguments(argumentList.Arguments.AddRange(items))); - } + public PrimaryConstructorBaseTypeSyntax AddArgumentListArguments(params ArgumentSyntax[] items) => WithArgumentList(this.ArgumentList.WithArguments(this.ArgumentList.Arguments.AddRange(items))); } /// Type parameter constraint clause. diff --git a/src/Compilers/CSharp/Portable/GlobalSuppressions.cs b/src/Compilers/CSharp/Portable/GlobalSuppressions.cs index 90b587b285b06..2f30945ffdf54 100644 --- a/src/Compilers/CSharp/Portable/GlobalSuppressions.cs +++ b/src/Compilers/CSharp/Portable/GlobalSuppressions.cs @@ -36,3 +36,5 @@ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DeconstructionPatternClause(Microsoft.CodeAnalysis.SeparatedSyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax})~Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionPatternClauseSyntax")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerType(Microsoft.CodeAnalysis.SeparatedSyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax})~Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax,System.Threading.CancellationToken)~Microsoft.CodeAnalysis.IMethodSymbol")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetSymbolInfo(Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax,System.Threading.CancellationToken)~Microsoft.CodeAnalysis.SymbolInfo")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetMemberGroup(Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax,System.Threading.CancellationToken)~System.Collections.Immutable.ImmutableArray{Microsoft.CodeAnalysis.ISymbol}")] diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs index 78ad6ac933582..6b8ce9bac91d9 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs @@ -1197,6 +1197,8 @@ private static void AppendMissingOptionalArguments( case SyntaxKind.BaseConstructorInitializer: case SyntaxKind.ThisConstructorInitializer: return new SourceLocation(((ConstructorInitializerSyntax)syntax).ArgumentList.OpenParenToken); + case SyntaxKind.PrimaryConstructorBaseType: + return new SourceLocation(((PrimaryConstructorBaseTypeSyntax)syntax).ArgumentList.OpenParenToken); case SyntaxKind.ElementAccessExpression: return new SourceLocation(((ElementAccessExpressionSyntax)syntax).ArgumentList.OpenBracketToken); case SyntaxKind.FromClause: diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 3f882b1b18ed0..53d6fe582c8be 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -1752,7 +1752,7 @@ private BaseListSyntax ParseBaseList(SyntaxToken typeKeyword, bool haveParameter } } - list.Add(_syntaxFactory.SimpleBaseType(firstType, argumentList)); + list.Add(argumentList is object ? _syntaxFactory.PrimaryConstructorBaseType(firstType, argumentList) : (BaseTypeSyntax)_syntaxFactory.SimpleBaseType(firstType)); // any additional types while (true) @@ -1766,7 +1766,7 @@ private BaseListSyntax ParseBaseList(SyntaxToken typeKeyword, bool haveParameter else if (this.CurrentToken.Kind == SyntaxKind.CommaToken || this.IsPossibleType()) { list.AddSeparator(this.EatToken(SyntaxKind.CommaToken)); - list.Add(_syntaxFactory.SimpleBaseType(this.ParseType(), argumentList: null)); + list.Add(_syntaxFactory.SimpleBaseType(this.ParseType())); continue; } else if (this.SkipBadBaseListTokens(ref colon, list, SyntaxKind.CommaToken) == PostSkipAction.Abort) @@ -5013,7 +5013,7 @@ private EnumDeclarationSyntax ParseEnumDeclaration(SyntaxList(); - tmpList.Add(_syntaxFactory.SimpleBaseType(type, argumentList: null)); + tmpList.Add(_syntaxFactory.SimpleBaseType(type)); baseList = _syntaxFactory.BaseList(colon, tmpList); _pool.Free(tmpList); } diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index a940e60957f16..5a357a9120c6e 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -1,6 +1,12 @@ *REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.ObjectCreationExpressionSyntax.ArgumentList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax *REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.ObjectCreationExpressionSyntax.Initializer.get -> Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax *REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.ObjectCreationExpressionSyntax.NewKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.AddArgumentListArguments(params Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.ArgumentList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList) -> Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.WithArgumentList(Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList) -> Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.WithType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.AddBaseListTypes(params Microsoft.CodeAnalysis.CSharp.Syntax.BaseTypeSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax @@ -23,10 +29,7 @@ Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithOpenBraceToken( Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithTypeParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax typeParameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax.AddArgumentListArguments(params Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax.ArgumentList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax.WithArgumentList(Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax +Microsoft.CodeAnalysis.CSharp.SyntaxKind.PrimaryConstructorBaseType = 9065 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RecordDeclaration = 9063 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RecordKeyword = 8444 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseObjectCreationExpressionSyntax.ArgumentList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax @@ -51,9 +54,13 @@ Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.WithLessThanToken Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.WithParameters(Microsoft.CodeAnalysis.SeparatedSyntaxList parameters) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax Microsoft.CodeAnalysis.CSharp.SyntaxKind.FunctionPointerType = 9056 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitPrimaryConstructorBaseType(Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRecordDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult +override Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult +override Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.Type.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax override Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult override Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList @@ -67,6 +74,9 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.Modifiers. override Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.OpenBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken override Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken override Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.TypeParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetSpeculativeSymbolInfo(this Microsoft.CodeAnalysis.SemanticModel semanticModel, int position, Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax constructorInitializer) -> Microsoft.CodeAnalysis.SymbolInfo +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetSymbolInfo(this Microsoft.CodeAnalysis.SemanticModel semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax constructorInitializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.SymbolInfo +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.TryGetSpeculativeSemanticModel(this Microsoft.CodeAnalysis.SemanticModel semanticModel, int position, Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax constructorInitializer, out Microsoft.CodeAnalysis.SemanticModel speculativeModel) -> bool static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerType(Microsoft.CodeAnalysis.SeparatedSyntaxList parameters = default(Microsoft.CodeAnalysis.SeparatedSyntaxList)) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerType(Microsoft.CodeAnalysis.SyntaxToken callingConvention, Microsoft.CodeAnalysis.SeparatedSyntaxList parameters) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerType(Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.SyntaxToken asteriskToken, Microsoft.CodeAnalysis.SyntaxToken callingConvention, Microsoft.CodeAnalysis.SyntaxToken lessThanToken, Microsoft.CodeAnalysis.SeparatedSyntaxList parameters, Microsoft.CodeAnalysis.SyntaxToken greaterThanToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax @@ -176,6 +186,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitObjectCreationExpress static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitObjectCreationExpression(Microsoft.CodeAnalysis.SyntaxToken newKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseTypeName(string text, int offset = 0, Microsoft.CodeAnalysis.ParseOptions options = null, bool consumeFullText = true) -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseTypeName(string text, int offset, bool consumeFullText) -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.PrimaryConstructorBaseType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.PrimaryConstructorBaseType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList) -> Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax @@ -183,12 +195,12 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.C static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitParenthesizedPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedPatternSyntax node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitPrimaryConstructorBaseType(Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRecordDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> TResult static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedPattern(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedPatternSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedPattern(Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern, Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedPatternSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RelationalPattern(Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RelationalPatternSyntax -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleBaseType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TypePattern(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.TypePatternSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UnaryPattern(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.UnaryPatternSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UnaryPattern(Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.UnaryPatternSyntax @@ -208,6 +220,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitWithExpression(Mi virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitBinaryPattern(Microsoft.CodeAnalysis.CSharp.Syntax.BinaryPatternSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitImplicitObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitParenthesizedPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedPatternSyntax node) -> TResult +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitPrimaryConstructorBaseType(Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRecordDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRelationalPattern(Microsoft.CodeAnalysis.CSharp.Syntax.RelationalPatternSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTypePattern(Microsoft.CodeAnalysis.CSharp.Syntax.TypePatternSyntax node) -> TResult diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs index 1a024747e2ef8..33c990215fd7b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs @@ -169,9 +169,9 @@ internal static LocalSymbol MakeLocalSymbolWithEnclosingContext( nodeToBind.Kind() == SyntaxKind.CasePatternSwitchLabel || nodeToBind.Kind() == SyntaxKind.ThisConstructorInitializer || nodeToBind.Kind() == SyntaxKind.BaseConstructorInitializer || - nodeToBind.Kind() == SyntaxKind.SimpleBaseType || // initializer for a record constructor + nodeToBind.Kind() == SyntaxKind.PrimaryConstructorBaseType || // initializer for a record constructor nodeToBind.Kind() == SyntaxKind.SwitchExpressionArm || - nodeToBind.Kind() == SyntaxKind.ArgumentList && nodeToBind.Parent is ConstructorInitializerSyntax || + nodeToBind.Kind() == SyntaxKind.ArgumentList && (nodeToBind.Parent is ConstructorInitializerSyntax || nodeToBind.Parent is PrimaryConstructorBaseTypeSyntax) || nodeToBind.Kind() == SyntaxKind.GotoCaseStatement || // for error recovery nodeToBind.Kind() == SyntaxKind.VariableDeclarator && new[] { SyntaxKind.LocalDeclarationStatement, SyntaxKind.ForStatement, SyntaxKind.UsingStatement, SyntaxKind.FixedStatement }. @@ -741,8 +741,8 @@ public LocalSymbolWithEnclosingContext( nodeToBind.Kind() == SyntaxKind.CasePatternSwitchLabel || nodeToBind.Kind() == SyntaxKind.ThisConstructorInitializer || nodeToBind.Kind() == SyntaxKind.BaseConstructorInitializer || - nodeToBind.Kind() == SyntaxKind.SimpleBaseType || // initializer for a record constructor - nodeToBind.Kind() == SyntaxKind.ArgumentList && nodeToBind.Parent is ConstructorInitializerSyntax || + nodeToBind.Kind() == SyntaxKind.PrimaryConstructorBaseType || // initializer for a record constructor + nodeToBind.Kind() == SyntaxKind.ArgumentList && (nodeToBind.Parent is ConstructorInitializerSyntax || nodeToBind.Parent is PrimaryConstructorBaseTypeSyntax) || nodeToBind.Kind() == SyntaxKind.VariableDeclarator || nodeToBind.Kind() == SyntaxKind.SwitchExpressionArm || nodeToBind.Kind() == SyntaxKind.GotoCaseStatement || @@ -769,12 +769,21 @@ protected override TypeWithAnnotations InferTypeOfVarVariable(DiagnosticBag diag var initializer = (ConstructorInitializerSyntax)_nodeToBind; _nodeBinder.BindConstructorInitializer(initializer, diagnostics); break; - case SyntaxKind.SimpleBaseType: - _nodeBinder.BindConstructorInitializer((SimpleBaseTypeSyntax)_nodeToBind, diagnostics); + case SyntaxKind.PrimaryConstructorBaseType: + _nodeBinder.BindConstructorInitializer((PrimaryConstructorBaseTypeSyntax)_nodeToBind, diagnostics); break; case SyntaxKind.ArgumentList: - var invocation = (ConstructorInitializerSyntax)_nodeToBind.Parent; - _nodeBinder.BindConstructorInitializer(invocation, diagnostics); + switch (_nodeToBind.Parent) + { + case ConstructorInitializerSyntax ctorInitializer: + _nodeBinder.BindConstructorInitializer(ctorInitializer, diagnostics); + break; + case PrimaryConstructorBaseTypeSyntax ctorInitializer: + _nodeBinder.BindConstructorInitializer(ctorInitializer, diagnostics); + break; + default: + throw ExceptionUtilities.UnexpectedValue(_nodeToBind.Parent); + } break; case SyntaxKind.CasePatternSwitchLabel: _nodeBinder.BindPatternSwitchLabelForInference((CasePatternSwitchLabelSyntax)_nodeToBind, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordConstructor.cs index 733a516bba650..3d083b323c07c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordConstructor.cs @@ -33,14 +33,7 @@ internal RecordDeclarationSyntax GetSyntax() protected override CSharpSyntaxNode? GetInitializer() { - var baseTypeSyntax = GetSyntax().BaseList?.Types.FirstOrDefault() as SimpleBaseTypeSyntax; - - if (baseTypeSyntax?.ArgumentList is object) - { - return baseTypeSyntax; - } - - return null; + return GetSyntax().PrimaryConstructorBaseType; } internal override bool IsExpressionBodied diff --git a/src/Compilers/CSharp/Portable/Syntax/LambdaUtilities.cs b/src/Compilers/CSharp/Portable/Syntax/LambdaUtilities.cs index 697435103fca4..c22abae528445 100644 --- a/src/Compilers/CSharp/Portable/Syntax/LambdaUtilities.cs +++ b/src/Compilers/CSharp/Portable/Syntax/LambdaUtilities.cs @@ -404,8 +404,6 @@ internal static bool IsClosureScope(SyntaxNode node) case SyntaxKind.IfStatement: case SyntaxKind.LockStatement: case SyntaxKind.ReturnStatement: - case SyntaxKind.ThisConstructorInitializer: - case SyntaxKind.BaseConstructorInitializer: case SyntaxKind.ThrowStatement: case SyntaxKind.WhileStatement: case SyntaxKind.YieldReturnStatement: diff --git a/src/Compilers/CSharp/Portable/Syntax/RecordDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/RecordDeclarationSyntax.cs index 19ac288a66fd9..0e2ab8a4a75d9 100644 --- a/src/Compilers/CSharp/Portable/Syntax/RecordDeclarationSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/RecordDeclarationSyntax.cs @@ -8,16 +8,11 @@ namespace Microsoft.CodeAnalysis.CSharp.Syntax { public partial class RecordDeclarationSyntax { - internal SimpleBaseTypeSyntax? BaseWithArguments + internal PrimaryConstructorBaseTypeSyntax? PrimaryConstructorBaseType { get { - if (BaseList?.Types.FirstOrDefault() is SimpleBaseTypeSyntax { ArgumentList: { } } firstBase) - { - return firstBase; - } - - return null; + return BaseList?.Types.FirstOrDefault() as PrimaryConstructorBaseTypeSyntax; } } } diff --git a/src/Compilers/CSharp/Portable/Syntax/SimpleBaseTypeSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/SimpleBaseTypeSyntax.cs deleted file mode 100644 index f6c8032094ff5..0000000000000 --- a/src/Compilers/CSharp/Portable/Syntax/SimpleBaseTypeSyntax.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -#nullable enable - -namespace Microsoft.CodeAnalysis.CSharp.Syntax -{ - public partial class SimpleBaseTypeSyntax - { - public SimpleBaseTypeSyntax Update(TypeSyntax type) - => Update(type, argumentList: null); - } -} diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index f7e0fecb2c6d6..1549c7356df01 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -3451,9 +3451,14 @@ - + + + + + + Type parameter constraint clause. diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxExtensions.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxExtensions.cs index e2132deefc706..77d1b868cc6db 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxExtensions.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxExtensions.cs @@ -250,6 +250,7 @@ private static bool IsInContextWhichNeedsDynamicAttribute(CSharpSyntaxNode node) case SyntaxKind.EventFieldDeclaration: case SyntaxKind.BaseList: case SyntaxKind.SimpleBaseType: + case SyntaxKind.PrimaryConstructorBaseType: return true; case SyntaxKind.Block: diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs index c7ecb7a3edfdd..d6794e6184813 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs @@ -186,6 +186,9 @@ public static bool IsInTypeOnlyContext(ExpressionSyntax node) case SimpleBaseType: return true; + case PrimaryConstructorBaseType: + return ((PrimaryConstructorBaseTypeSyntax)parent).Type == node; + case CrefParameter: return true; @@ -313,6 +316,7 @@ public static bool IsNamedArgumentName(SyntaxNode node) case Attribute: case BaseConstructorInitializer: case ThisConstructorInitializer: + case PrimaryConstructorBaseType: return true; default: return false; diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index b25aa6cbd8093..fde6f519abf04 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -621,6 +621,8 @@ public enum SyntaxKind : ushort WithExpression = 9061, WithInitializerExpression = 9062, - RecordDeclaration = 9063 + RecordDeclaration = 9063, + + PrimaryConstructorBaseType = 9065, } } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs index 9651b6d3d119b..5dab21460a44a 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs @@ -78,14 +78,11 @@ internal static bool CanHaveAssociatedLocalBinder(this SyntaxNode syntax) case SyntaxKind.BaseConstructorInitializer: case SyntaxKind.ThisConstructorInitializer: case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.PrimaryConstructorBaseType: return true; case SyntaxKind.RecordDeclaration: return ((RecordDeclarationSyntax)syntax).ParameterList is object; - case SyntaxKind.SimpleBaseType: - return ((SimpleBaseTypeSyntax)syntax).ArgumentList is object && - syntax.Parent?.Parent is RecordDeclarationSyntax recordDecl && - recordDecl.ParameterList is object && recordDecl.BaseWithArguments == syntax; default: return syntax is StatementSyntax || IsValidScopeDesignator(syntax as ExpressionSyntax); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index ca68d91577e0d..2627940b0f6d1 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -4,6 +4,7 @@ #nullable enable +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -7033,6 +7034,8 @@ public static void Main() var c = new C(1, 2); Console.WriteLine(c.Z); } + + C(int X, int Y, int Z) : this(X, Y) {} }"; var verifier = CompileAndVerify(src, expectedOutput: @" 1 @@ -7077,10 +7080,42 @@ .maxstack 3 Assert.Contains(symbol, model.LookupSymbols(x.SpanStart, name: "X")); Assert.Contains("X", model.LookupNames(x.SpanStart)); - var baseWithargs = tree.GetRoot().DescendantNodes().OfType().Single(); - Assert.Equal("Base(X, Y)", baseWithargs.ToString()); - Assert.Null(model.GetTypeInfo(baseWithargs).Type); - Assert.Null(model.GetSymbolInfo(baseWithargs).Symbol); + { + var baseWithargs = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal("Base(X, Y)", baseWithargs.ToString()); + Assert.Equal("Base", model.GetTypeInfo(baseWithargs.Type).Type.ToTestDisplayString()); + Assert.Equal(TypeInfo.None, model.GetTypeInfo(baseWithargs)); + Assert.Equal("Base..ctor(System.Int32 X, System.Int32 Y)", model.GetSymbolInfo((SyntaxNode)baseWithargs).Symbol.ToTestDisplayString()); + Assert.Equal("Base..ctor(System.Int32 X, System.Int32 Y)", model.GetSymbolInfo(baseWithargs).Symbol.ToTestDisplayString()); + Assert.Equal("Base..ctor(System.Int32 X, System.Int32 Y)", CSharpExtensions.GetSymbolInfo(model, baseWithargs).Symbol.ToTestDisplayString()); + + Assert.Empty(model.GetMemberGroup((SyntaxNode)baseWithargs)); + Assert.Empty(model.GetMemberGroup(baseWithargs)); + + model = comp.GetSemanticModel(tree); + Assert.Equal("Base..ctor(System.Int32 X, System.Int32 Y)", model.GetSymbolInfo((SyntaxNode)baseWithargs).Symbol.ToTestDisplayString()); + model = comp.GetSemanticModel(tree); + Assert.Equal("Base..ctor(System.Int32 X, System.Int32 Y)", model.GetSymbolInfo(baseWithargs).Symbol.ToTestDisplayString()); + model = comp.GetSemanticModel(tree); + Assert.Equal("Base..ctor(System.Int32 X, System.Int32 Y)", CSharpExtensions.GetSymbolInfo(model, baseWithargs).Symbol.ToTestDisplayString()); + + model = comp.GetSemanticModel(tree); + Assert.Empty(model.GetMemberGroup((SyntaxNode)baseWithargs)); + model = comp.GetSemanticModel(tree); + Assert.Empty(model.GetMemberGroup(baseWithargs)); + model = comp.GetSemanticModel(tree); + } + { + var baseWithargs = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal(": this(X, Y)", baseWithargs.ToString()); + Assert.Equal("C..ctor(System.Int32 X, System.Int32 Y)", model.GetSymbolInfo((SyntaxNode)baseWithargs).Symbol.ToTestDisplayString()); + Assert.Equal("C..ctor(System.Int32 X, System.Int32 Y)", model.GetSymbolInfo(baseWithargs).Symbol.ToTestDisplayString()); + Assert.Equal("C..ctor(System.Int32 X, System.Int32 Y)", CSharpExtensions.GetSymbolInfo(model, baseWithargs).Symbol.ToTestDisplayString()); + + Assert.Empty(model.GetMemberGroup((SyntaxNode)baseWithargs).Select(m => m.ToTestDisplayString())); + Assert.Empty(model.GetMemberGroup(baseWithargs).Select(m => m.ToTestDisplayString())); + Assert.Empty(CSharpExtensions.GetMemberGroup(model, baseWithargs).Select(m => m.ToTestDisplayString())); + } } [Fact] @@ -7825,6 +7860,327 @@ private static int Test(int x, out int y) ); } + [Fact] + public void BaseArguments_19() + { + var src = @" +record Base +{ + public Base(int X) + { + } + + public Base() {} +} + +record C(int X, int Y) : Base(GetInt(X, out var xx) + xx, Y), I +{ + C(int X, int Y, int Z) : this(X, Y, Z, 1) { return; } + + static int GetInt(int x1, out int x2) + { + throw null; + } +} + +interface I {} +"; + + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (11,30): error CS1729: 'Base' does not contain a constructor that takes 2 arguments + // record C(int X, int Y) : Base(GetInt(X, out var xx) + xx, Y) + Diagnostic(ErrorCode.ERR_BadCtorArgCount, "(GetInt(X, out var xx) + xx, Y)").WithArguments("Base", "2").WithLocation(11, 30), + // (13,30): error CS1729: 'C' does not contain a constructor that takes 4 arguments + // C(int X, int Y, int Z) : this(X, Y, Z, 1) {} + Diagnostic(ErrorCode.ERR_BadCtorArgCount, "this").WithArguments("C", "4").WithLocation(13, 30) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + SymbolInfo symbolInfo; + PrimaryConstructorBaseTypeSyntax speculativePrimaryInitializer; + ConstructorInitializerSyntax speculativeBaseInitializer; + + { + var baseWithargs = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal("Base(GetInt(X, out var xx) + xx, Y)", baseWithargs.ToString()); + Assert.Equal("Base", model.GetTypeInfo(baseWithargs.Type).Type.ToTestDisplayString()); + Assert.Equal(TypeInfo.None, model.GetTypeInfo(baseWithargs)); + symbolInfo = model.GetSymbolInfo((SyntaxNode)baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + string[] candidates = new[] { "Base..ctor(System.Int32 X)", "Base..ctor()", "Base..ctor(Base )" }; + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + symbolInfo = model.GetSymbolInfo(baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + symbolInfo = CSharpExtensions.GetSymbolInfo(model, baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + + Assert.Empty(model.GetMemberGroup((SyntaxNode)baseWithargs)); + Assert.Empty(model.GetMemberGroup(baseWithargs)); + + model = comp.GetSemanticModel(tree); + symbolInfo = model.GetSymbolInfo((SyntaxNode)baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + model = comp.GetSemanticModel(tree); + symbolInfo = model.GetSymbolInfo(baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + model = comp.GetSemanticModel(tree); + symbolInfo = CSharpExtensions.GetSymbolInfo(model, baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + + model = comp.GetSemanticModel(tree); + Assert.Empty(model.GetMemberGroup((SyntaxNode)baseWithargs)); + model = comp.GetSemanticModel(tree); + Assert.Empty(model.GetMemberGroup(baseWithargs)); + model = comp.GetSemanticModel(tree); + + SemanticModel speculativeModel; + speculativePrimaryInitializer = baseWithargs.WithArgumentList(baseWithargs.ArgumentList.WithArguments(baseWithargs.ArgumentList.Arguments.RemoveAt(1))); + + speculativeBaseInitializer = SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, speculativePrimaryInitializer.ArgumentList); + Assert.False(model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativeBaseInitializer, out _)); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativeBaseInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativeBaseInitializer); + Assert.Equal(SymbolInfo.None, symbolInfo); + + Assert.False(model.TryGetSpeculativeSemanticModel(tree.GetRoot().DescendantNodes().OfType().Single().SpanStart, + speculativeBaseInitializer, out _)); + + var otherBasePosition = ((BaseListSyntax)baseWithargs.Parent!).Types[1].SpanStart; + Assert.False(model.TryGetSpeculativeSemanticModel(otherBasePosition, speculativePrimaryInitializer, out _)); + + Assert.True(model.TryGetSpeculativeSemanticModel(baseWithargs.SpanStart, speculativePrimaryInitializer, out speculativeModel!)); + Assert.Equal("Base..ctor(System.Int32 X)", speculativeModel!.GetSymbolInfo((SyntaxNode)speculativePrimaryInitializer).Symbol.ToTestDisplayString()); + Assert.Equal("Base..ctor(System.Int32 X)", speculativeModel.GetSymbolInfo(speculativePrimaryInitializer).Symbol.ToTestDisplayString()); + Assert.Equal("Base..ctor(System.Int32 X)", CSharpExtensions.GetSymbolInfo(speculativeModel, speculativePrimaryInitializer).Symbol.ToTestDisplayString()); + + Assert.True(model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativePrimaryInitializer, out speculativeModel!)); + + var xxDecl = OutVarTests.GetOutVarDeclaration(speculativePrimaryInitializer.SyntaxTree, "xx"); + var xxRef = OutVarTests.GetReferences(speculativePrimaryInitializer.SyntaxTree, "xx").ToArray(); + Assert.Equal(1, xxRef.Length); + OutVarTests.VerifyModelForOutVar(speculativeModel, xxDecl, xxRef); + + Assert.Equal("Base..ctor(System.Int32 X)", speculativeModel!.GetSymbolInfo((SyntaxNode)speculativePrimaryInitializer).Symbol.ToTestDisplayString()); + Assert.Equal("Base..ctor(System.Int32 X)", speculativeModel.GetSymbolInfo(speculativePrimaryInitializer).Symbol.ToTestDisplayString()); + Assert.Equal("Base..ctor(System.Int32 X)", CSharpExtensions.GetSymbolInfo(speculativeModel, speculativePrimaryInitializer).Symbol.ToTestDisplayString()); + + Assert.Throws(() => model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (PrimaryConstructorBaseTypeSyntax)null!, out _)); + Assert.Throws(() => model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, baseWithargs, out _)); + + symbolInfo = model.GetSpeculativeSymbolInfo(otherBasePosition, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, otherBasePosition, speculativePrimaryInitializer); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.SpanStart, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal("Base..ctor(System.Int32 X)", symbolInfo.Symbol.ToTestDisplayString()); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, baseWithargs.SpanStart, speculativePrimaryInitializer); + Assert.Equal("Base..ctor(System.Int32 X)", symbolInfo.Symbol.ToTestDisplayString()); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal("Base..ctor(System.Int32 X)", symbolInfo.Symbol.ToTestDisplayString()); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativePrimaryInitializer); + Assert.Equal("Base..ctor(System.Int32 X)", symbolInfo.Symbol.ToTestDisplayString()); + + Assert.Equal(TypeInfo.None, model.GetSpeculativeTypeInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression)); + Assert.Equal(TypeInfo.None, model.GetSpeculativeTypeInfo(tree.GetRoot().DescendantNodes().OfType().Single().ArgumentList.OpenParenToken.SpanStart, + (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression)); + } + { + var baseWithargs = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal(": this(X, Y, Z, 1)", baseWithargs.ToString()); + symbolInfo = model.GetSymbolInfo((SyntaxNode)baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + string[] candidates = new[] { "C..ctor(System.Int32 X, System.Int32 Y, System.Int32 Z)", "C..ctor(System.Int32 X, System.Int32 Y)", "C..ctor(C )" }; + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + symbolInfo = model.GetSymbolInfo(baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + symbolInfo = CSharpExtensions.GetSymbolInfo(model, baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + + Assert.Empty(model.GetMemberGroup((SyntaxNode)baseWithargs).Select(m => m.ToTestDisplayString())); + Assert.Empty(model.GetMemberGroup(baseWithargs).Select(m => m.ToTestDisplayString())); + Assert.Empty(CSharpExtensions.GetMemberGroup(model, baseWithargs).Select(m => m.ToTestDisplayString())); + + Assert.False(model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativePrimaryInitializer, out _)); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativePrimaryInitializer); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativeBaseInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal("Base..ctor(System.Int32 X)", symbolInfo.Symbol.ToTestDisplayString()); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativeBaseInitializer); + Assert.Equal("Base..ctor(System.Int32 X)", symbolInfo.Symbol.ToTestDisplayString()); + + Assert.Equal(TypeInfo.None, model.GetSpeculativeTypeInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression)); + } + } + + [Fact] + public void BaseArguments_20() + { + var src = @" +class Base +{ + public Base(int X) + { + } + + public Base() {} +} + +class C : Base(GetInt(X, out var xx) + xx, Y), I +{ + C(int X, int Y, int Z) : base(X, Y, Z, 1) { return; } + + static int GetInt(int x1, out int x2) + { + throw null; + } +} + +interface I {} +"; + + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (11,15): error CS8861: Unexpected argument list. + // class C : Base(GetInt(X, out var xx) + xx, Y), I + Diagnostic(ErrorCode.ERR_UnexpectedArgumentList, "(").WithLocation(11, 15), + // (13,30): error CS1729: 'Base' does not contain a constructor that takes 4 arguments + // C(int X, int Y, int Z) : base(X, Y, Z, 1) { return; } + Diagnostic(ErrorCode.ERR_BadCtorArgCount, "base").WithArguments("Base", "4").WithLocation(13, 30) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + SymbolInfo symbolInfo; + PrimaryConstructorBaseTypeSyntax speculativePrimaryInitializer; + ConstructorInitializerSyntax speculativeBaseInitializer; + + { + var baseWithargs = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal("Base(GetInt(X, out var xx) + xx, Y)", baseWithargs.ToString()); + Assert.Equal("Base", model.GetTypeInfo(baseWithargs.Type).Type.ToTestDisplayString()); + Assert.Equal(TypeInfo.None, model.GetTypeInfo(baseWithargs)); + symbolInfo = model.GetSymbolInfo((SyntaxNode)baseWithargs); + Assert.Equal(SymbolInfo.None, symbolInfo); + symbolInfo = model.GetSymbolInfo(baseWithargs); + Assert.Equal(SymbolInfo.None, symbolInfo); + symbolInfo = CSharpExtensions.GetSymbolInfo(model, baseWithargs); + Assert.Equal(SymbolInfo.None, symbolInfo); + + Assert.Empty(model.GetMemberGroup((SyntaxNode)baseWithargs)); + Assert.Empty(model.GetMemberGroup(baseWithargs)); + + speculativePrimaryInitializer = baseWithargs.WithArgumentList(baseWithargs.ArgumentList.WithArguments(baseWithargs.ArgumentList.Arguments.RemoveAt(1))); + + speculativeBaseInitializer = SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, speculativePrimaryInitializer.ArgumentList); + Assert.False(model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativeBaseInitializer, out _)); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativeBaseInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativeBaseInitializer); + Assert.Equal(SymbolInfo.None, symbolInfo); + + Assert.False(model.TryGetSpeculativeSemanticModel(tree.GetRoot().DescendantNodes().OfType().Single().SpanStart, + speculativeBaseInitializer, out _)); + + var otherBasePosition = ((BaseListSyntax)baseWithargs.Parent!).Types[1].SpanStart; + Assert.False(model.TryGetSpeculativeSemanticModel(otherBasePosition, speculativePrimaryInitializer, out _)); + + Assert.False(model.TryGetSpeculativeSemanticModel(baseWithargs.SpanStart, speculativePrimaryInitializer, out _)); + Assert.False(model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativePrimaryInitializer, out _)); + + Assert.Throws(() => model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (PrimaryConstructorBaseTypeSyntax)null!, out _)); + Assert.Throws(() => model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, baseWithargs, out _)); + + symbolInfo = model.GetSpeculativeSymbolInfo(otherBasePosition, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, otherBasePosition, speculativePrimaryInitializer); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.SpanStart, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, baseWithargs.SpanStart, speculativePrimaryInitializer); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativePrimaryInitializer); + Assert.Equal(SymbolInfo.None, symbolInfo); + + Assert.Equal(TypeInfo.None, model.GetSpeculativeTypeInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression)); + Assert.Equal(TypeInfo.None, model.GetSpeculativeTypeInfo(tree.GetRoot().DescendantNodes().OfType().Single().ArgumentList.OpenParenToken.SpanStart, + (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression)); + } + { + var baseWithargs = tree.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal(": base(X, Y, Z, 1)", baseWithargs.ToString()); + symbolInfo = model.GetSymbolInfo((SyntaxNode)baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + string[] candidates = new[] { "Base..ctor(System.Int32 X)", "Base..ctor()" }; + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + symbolInfo = model.GetSymbolInfo(baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + symbolInfo = CSharpExtensions.GetSymbolInfo(model, baseWithargs); + Assert.Null(symbolInfo.Symbol); + Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); + Assert.Equal(candidates, symbolInfo.CandidateSymbols.Select(m => m.ToTestDisplayString())); + + Assert.Empty(model.GetMemberGroup((SyntaxNode)baseWithargs).Select(m => m.ToTestDisplayString())); + Assert.Empty(model.GetMemberGroup(baseWithargs).Select(m => m.ToTestDisplayString())); + Assert.Empty(CSharpExtensions.GetMemberGroup(model, baseWithargs).Select(m => m.ToTestDisplayString())); + + Assert.False(model.TryGetSpeculativeSemanticModel(baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativePrimaryInitializer, out _)); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativePrimaryInitializer); + Assert.Equal(SymbolInfo.None, symbolInfo); + + symbolInfo = model.GetSpeculativeSymbolInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativeBaseInitializer, SpeculativeBindingOption.BindAsExpression); + Assert.Equal("Base..ctor(System.Int32 X)", symbolInfo.Symbol.ToTestDisplayString()); + + symbolInfo = CSharpExtensions.GetSpeculativeSymbolInfo(model, baseWithargs.ArgumentList.OpenParenToken.SpanStart, speculativeBaseInitializer); + Assert.Equal("Base..ctor(System.Int32 X)", symbolInfo.Symbol.ToTestDisplayString()); + + Assert.Equal(TypeInfo.None, model.GetSpeculativeTypeInfo(baseWithargs.ArgumentList.OpenParenToken.SpanStart, (SyntaxNode)speculativePrimaryInitializer, SpeculativeBindingOption.BindAsExpression)); + } + } + [Fact(Skip = "record struct")] public void Equality_01() { diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs index e7080f3e3a947..f66303e94ff84 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs @@ -2145,7 +2145,7 @@ void M(int x) SemanticModel speculativeModel; Assert.Throws(() => model.TryGetSpeculativeSemanticModel(statement.SpanStart, statement: null, speculativeModel: out speculativeModel)); - Assert.Throws(() => model.TryGetSpeculativeSemanticModel(statement.SpanStart, constructorInitializer: null, speculativeModel: out speculativeModel)); + Assert.Throws(() => model.TryGetSpeculativeSemanticModel(statement.SpanStart, constructorInitializer: (ConstructorInitializerSyntax)null, speculativeModel: out speculativeModel)); Assert.Throws(() => model.TryGetSpeculativeSemanticModel(statement.SpanStart, attribute: null, speculativeModel: out speculativeModel)); // Speculate on a node from the same syntax tree. diff --git a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs index 68752b7c4a6ab..1fe6a5b00fce9 100644 --- a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs +++ b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs @@ -485,7 +485,10 @@ private static Syntax.InternalSyntax.BaseListSyntax GenerateBaseList() => InternalSyntaxFactory.BaseList(InternalSyntaxFactory.Token(SyntaxKind.ColonToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList()); private static Syntax.InternalSyntax.SimpleBaseTypeSyntax GenerateSimpleBaseType() - => InternalSyntaxFactory.SimpleBaseType(GenerateIdentifierName(), null); + => InternalSyntaxFactory.SimpleBaseType(GenerateIdentifierName()); + + private static Syntax.InternalSyntax.PrimaryConstructorBaseTypeSyntax GeneratePrimaryConstructorBaseType() + => InternalSyntaxFactory.PrimaryConstructorBaseType(GenerateIdentifierName(), GenerateArgumentList()); private static Syntax.InternalSyntax.TypeParameterConstraintClauseSyntax GenerateTypeParameterConstraintClause() => InternalSyntaxFactory.TypeParameterConstraintClause(InternalSyntaxFactory.Token(SyntaxKind.WhereKeyword), GenerateIdentifierName(), InternalSyntaxFactory.Token(SyntaxKind.ColonToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList()); @@ -2690,7 +2693,17 @@ public void TestSimpleBaseTypeFactoryAndProperties() var node = GenerateSimpleBaseType(); Assert.NotNull(node.Type); - Assert.Null(node.ArgumentList); + + AttachAndCheckDiagnostics(node); + } + + [Fact] + public void TestPrimaryConstructorBaseTypeFactoryAndProperties() + { + var node = GeneratePrimaryConstructorBaseType(); + + Assert.NotNull(node.Type); + Assert.NotNull(node.ArgumentList); AttachAndCheckDiagnostics(node); } @@ -7700,6 +7713,32 @@ public void TestSimpleBaseTypeIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestPrimaryConstructorBaseTypeTokenDeleteRewriter() + { + var oldNode = GeneratePrimaryConstructorBaseType(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestPrimaryConstructorBaseTypeIdentityRewriter() + { + var oldNode = GeneratePrimaryConstructorBaseType(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestTypeParameterConstraintClauseTokenDeleteRewriter() { @@ -9870,7 +9909,10 @@ private static BaseListSyntax GenerateBaseList() => SyntaxFactory.BaseList(SyntaxFactory.Token(SyntaxKind.ColonToken), new SeparatedSyntaxList()); private static SimpleBaseTypeSyntax GenerateSimpleBaseType() - => SyntaxFactory.SimpleBaseType(GenerateIdentifierName(), default(ArgumentListSyntax)); + => SyntaxFactory.SimpleBaseType(GenerateIdentifierName()); + + private static PrimaryConstructorBaseTypeSyntax GeneratePrimaryConstructorBaseType() + => SyntaxFactory.PrimaryConstructorBaseType(GenerateIdentifierName(), GenerateArgumentList()); private static TypeParameterConstraintClauseSyntax GenerateTypeParameterConstraintClause() => SyntaxFactory.TypeParameterConstraintClause(SyntaxFactory.Token(SyntaxKind.WhereKeyword), GenerateIdentifierName(), SyntaxFactory.Token(SyntaxKind.ColonToken), new SeparatedSyntaxList()); @@ -12075,7 +12117,17 @@ public void TestSimpleBaseTypeFactoryAndProperties() var node = GenerateSimpleBaseType(); Assert.NotNull(node.Type); - Assert.Null(node.ArgumentList); + var newNode = node.WithType(node.Type); + Assert.Equal(node, newNode); + } + + [Fact] + public void TestPrimaryConstructorBaseTypeFactoryAndProperties() + { + var node = GeneratePrimaryConstructorBaseType(); + + Assert.NotNull(node.Type); + Assert.NotNull(node.ArgumentList); var newNode = node.WithType(node.Type).WithArgumentList(node.ArgumentList); Assert.Equal(node, newNode); } @@ -17085,6 +17137,32 @@ public void TestSimpleBaseTypeIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestPrimaryConstructorBaseTypeTokenDeleteRewriter() + { + var oldNode = GeneratePrimaryConstructorBaseType(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestPrimaryConstructorBaseTypeIdentityRewriter() + { + var oldNode = GeneratePrimaryConstructorBaseType(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestTypeParameterConstraintClauseTokenDeleteRewriter() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs index e18ae00885564..60c4e35205323 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs @@ -1499,7 +1499,7 @@ public void Base_01( N(SyntaxKind.BaseList); { N(SyntaxKind.ColonToken); - N(SyntaxKind.SimpleBaseType); + N(withBaseArguments ? SyntaxKind.PrimaryConstructorBaseType : SyntaxKind.SimpleBaseType); { N(SyntaxKind.IdentifierName); { @@ -1797,7 +1797,7 @@ public void Base_05() N(SyntaxKind.BaseList); { N(SyntaxKind.ColonToken); - N(SyntaxKind.SimpleBaseType); + N(SyntaxKind.PrimaryConstructorBaseType); { N(SyntaxKind.IdentifierName); {