@@ -449,11 +449,10 @@ private void ParseNamespaceBody(ref SyntaxToken openBrace, ref NamespaceBodyBuil
449449 }
450450
451451 case SyntaxKind.UsingKeyword:
452- if (isGlobal && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken)
452+ if (isGlobal && ( this.PeekToken(1).Kind == SyntaxKind.OpenParenToken || (!IsScript && IsPossibleTopLevelUsingLocalDeclarationStatement())) )
453453 {
454- // incomplete members must be processed before we add any nodes to the body:
455- AddIncompleteMembers(ref pendingIncompleteMembers, ref body);
456- body.Members.Add(adjustStateAndReportStatementOutOfOrder(ref seen, ParseTopLevelUsingStatement()));
454+ // Top-level using statement or using local declaration
455+ goto default;
457456 }
458457 else
459458 {
@@ -591,20 +590,6 @@ MemberDeclarationSyntax adjustStateAndReportStatementOutOfOrder(ref NamespacePar
591590 }
592591 }
593592
594- [MethodImpl(MethodImplOptions.NoInlining)]
595- private GlobalStatementSyntax ParseTopLevelUsingStatement()
596- {
597- bool wasInAsync = IsInAsync;
598- if (!IsScript)
599- {
600- IsInAsync = true; // We are implicitly in an async context
601- }
602-
603- var topLevelUsingStatement = CheckSimpleProgramsFeatureAvailability(_syntaxFactory.GlobalStatement(ParseUsingStatement(attributes: default)));
604- IsInAsync = wasInAsync;
605- return topLevelUsingStatement;
606- }
607-
608593 private GlobalStatementSyntax CheckSimpleProgramsFeatureAvailability(GlobalStatementSyntax globalStatementSyntax)
609594 {
610595 if (IsScript || _checkedSimpleProgramsFeatureAvailability)
@@ -2374,7 +2359,6 @@ static bool isAcceptableNonDeclarationStatement(StatementSyntax statement, bool
23742359 switch (statement?.Kind)
23752360 {
23762361 case null:
2377- case SyntaxKind.LocalDeclarationStatement:
23782362 case SyntaxKind.LocalFunctionStatement:
23792363 case SyntaxKind.ExpressionStatement when
23802364 !isScript &&
@@ -2386,6 +2370,9 @@ static bool isAcceptableNonDeclarationStatement(StatementSyntax statement, bool
23862370
23872371 return false;
23882372
2373+ case SyntaxKind.LocalDeclarationStatement:
2374+ return !isScript && ((LocalDeclarationStatementSyntax)statement).UsingKeyword is object;
2375+
23892376 default:
23902377 return true;
23912378 }
@@ -6957,6 +6944,11 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel)
69576944 return true;
69586945 }
69596946
6947+ return IsPossibleFirstTypedIdentifierInLocaDeclarationStatement(isGlobalScriptLevel);
6948+ }
6949+
6950+ private bool IsPossibleFirstTypedIdentifierInLocaDeclarationStatement(bool isGlobalScriptLevel)
6951+ {
69606952 bool? typedIdentifier = IsPossibleTypedIdentifierStart(this.CurrentToken, this.PeekToken(1), allowThisKeyword: false);
69616953 if (typedIdentifier != null)
69626954 {
@@ -6978,6 +6970,8 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel)
69786970 //
69796971 // Note that we explicitly do this check when we see that the code spreads over multiple
69806972 // lines. We don't want this if the user has actually written "X.Y z"
6973+ var tk = this.CurrentToken.ContextualKind;
6974+
69816975 if (tk == SyntaxKind.IdentifierToken)
69826976 {
69836977 var token1 = PeekToken(1);
@@ -7053,6 +7047,53 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel)
70537047 }
70547048 }
70557049
7050+ private bool IsPossibleTopLevelUsingLocalDeclarationStatement()
7051+ {
7052+ if (this.CurrentToken.Kind != SyntaxKind.UsingKeyword)
7053+ {
7054+ return false;
7055+ }
7056+
7057+ var tk = PeekToken(1).Kind;
7058+
7059+ if (tk == SyntaxKind.RefKeyword)
7060+ {
7061+ return true;
7062+ }
7063+
7064+ if (IsDeclarationModifier(tk)) // treat `const int x = 2;` as a local variable declaration
7065+ {
7066+ if (tk != SyntaxKind.StaticKeyword) // For `static` we still need to make sure we have a typed identifier after it, because `using static type;` is a valid using directive.
7067+ {
7068+ return true;
7069+ }
7070+ }
7071+ else if (SyntaxFacts.IsPredefinedType(tk))
7072+ {
7073+ return true;
7074+ }
7075+
7076+ var resetPoint = this.GetResetPoint();
7077+ try
7078+ {
7079+ // Skip 'using' keyword
7080+ EatToken();
7081+
7082+ if (tk == SyntaxKind.StaticKeyword)
7083+ {
7084+ // Skip 'static' keyword
7085+ EatToken();
7086+ }
7087+
7088+ return IsPossibleFirstTypedIdentifierInLocaDeclarationStatement(isGlobalScriptLevel: false);
7089+ }
7090+ finally
7091+ {
7092+ this.Reset(ref resetPoint);
7093+ this.Release(ref resetPoint);
7094+ }
7095+ }
7096+
70567097 // Looks ahead for a declaration of a field, property or method declaration following a nullable type T?.
70577098 private bool IsPossibleDeclarationStatementFollowingNullableType()
70587099 {
0 commit comments