Skip to content

Commit dced5e0

Browse files
johnniwintherCommit Queue
authored andcommitted
[cfe] Add LocalTypeParameterScope
This cleans up the LocalScope interface and the handling of named function expressions. Change-Id: Id0432910a9e65d8ae966dfab67c66248639d241a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/419842 Reviewed-by: Chloe Stefantsova <[email protected]> Commit-Queue: Johnni Winther <[email protected]>
1 parent bdf0f64 commit dced5e0

File tree

42 files changed

+284
-108
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+284
-108
lines changed

pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -966,8 +966,9 @@ class ForwardingListener implements Listener {
966966
}
967967

968968
@override
969-
void endFunctionName(Token beginToken, Token token) {
970-
listener?.endFunctionName(beginToken, token);
969+
void endFunctionName(
970+
Token beginToken, Token token, bool isFunctionExpression) {
971+
listener?.endFunctionName(beginToken, token, isFunctionExpression);
971972
}
972973

973974
@override

pkg/_fe_analyzer_shared/lib/src/parser/listener.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,23 @@ class Listener implements UnescapeErrorListener {
812812

813813
void beginFunctionName(Token token) {}
814814

815-
void endFunctionName(Token beginToken, Token token) {
815+
/// The end of the function name in either a local function declaration, like
816+
/// 'local' in:
817+
///
818+
/// void m() {
819+
/// void local() {}
820+
/// }
821+
///
822+
/// or an erroneous function expression, like 'local' in:
823+
///
824+
/// void m() {
825+
/// var f = void local() {};
826+
/// }
827+
///
828+
/// The boolean [isFunctionExpression] indicates that we are in the latter
829+
/// case.
830+
void endFunctionName(
831+
Token beginToken, Token token, bool isFunctionExpression) {
816832
logEvent("FunctionName");
817833
}
818834

pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5222,7 +5222,7 @@ class Parser {
52225222
reportRecoverableError(
52235223
beforeName.next!, codes.messageNamedFunctionExpression);
52245224
}
5225-
listener.endFunctionName(begin, token);
5225+
listener.endFunctionName(begin, token, isFunctionExpression);
52265226
token = parseFormalParametersRequiredOpt(formals, MemberKind.Local);
52275227
token = parseInitializersOpt(token);
52285228
token = parseAsyncOptBody(

pkg/analyzer/lib/src/fasta/ast_builder.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2105,7 +2105,8 @@ class AstBuilder extends StackListener {
21052105
}
21062106

21072107
@override
2108-
void endFunctionName(Token beginToken, Token token) {
2108+
void endFunctionName(
2109+
Token beginToken, Token token, bool isFunctionExpression) {
21092110
debugEvent("FunctionName");
21102111
}
21112112

pkg/analyzer/test/generated/parser_fasta_listener.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -981,9 +981,9 @@ class ForwardingTestListener extends ForwardingListener {
981981
}
982982

983983
@override
984-
void endFunctionName(Token beginToken, Token token) {
984+
void endFunctionName(Token beginToken, Token token, bool isFunctionExpression) {
985985
end('FunctionName');
986-
super.endFunctionName(beginToken, token);
986+
super.endFunctionName(beginToken, token, isFunctionExpression);
987987
}
988988

989989
@override

pkg/front_end/lib/src/base/local_scope.dart

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import '../builder/builder.dart';
66
import '../builder/declaration_builders.dart';
7+
import '../builder/variable_builder.dart';
78
import 'scope.dart';
89

910
abstract class LocalScope implements LookupScope {
@@ -27,9 +28,7 @@ abstract class LocalScope implements LookupScope {
2728
/// If name was used previously in this scope, this method returns the read
2829
/// offsets which can be used for reporting a compile-time error about
2930
/// [name] being used before its declared.
30-
List<int>? declare(String name, Builder builder);
31-
32-
void addLocalVariable(String name, Builder builder);
31+
List<int>? declare(String name, VariableBuilder builder);
3332

3433
@override
3534
Builder? lookupGetable(String name, int charOffset, Uri fileUri);
@@ -117,7 +116,7 @@ final class LocalScopeImpl extends BaseLocalScope
117116

118117
/// Names declared in this scope.
119118
@override
120-
Map<String, Builder>? _local;
119+
Map<String, VariableBuilder>? _local;
121120

122121
@override
123122
Map<String, List<int>>? usedNames;
@@ -128,12 +127,7 @@ final class LocalScopeImpl extends BaseLocalScope
128127
LocalScopeImpl(this._parent, this.kind, this.classNameOrDebugName);
129128

130129
@override
131-
void addLocalVariable(String name, Builder builder) {
132-
(_local ??= {})[name] = builder;
133-
}
134-
135-
@override
136-
List<int>? declare(String name, Builder builder) {
130+
List<int>? declare(String name, VariableBuilder builder) {
137131
List<int>? previousOffsets = usedNames?[name];
138132
if (previousOffsets != null && previousOffsets.isNotEmpty) {
139133
return previousOffsets;
@@ -157,12 +151,7 @@ final class LocalScopeImpl extends BaseLocalScope
157151

158152
mixin ImmutableLocalScopeMixin implements LocalScope {
159153
@override
160-
void addLocalVariable(String name, Builder builder) {
161-
throw new UnsupportedError('$runtimeType($kind).addLocalMember');
162-
}
163-
164-
@override
165-
List<int>? declare(String name, Builder builder) {
154+
List<int>? declare(String name, VariableBuilder builder) {
166155
throw new UnsupportedError('$runtimeType($kind).declare');
167156
}
168157

@@ -171,6 +160,34 @@ mixin ImmutableLocalScopeMixin implements LocalScope {
171160
Map<String, List<int>>? get usedNames => null;
172161
}
173162

163+
final class LocalTypeParameterScope extends BaseLocalScope
164+
with LookupScopeMixin, ImmutableLocalScopeMixin, LocalScopeMixin {
165+
@override
166+
final LocalScope? _parent;
167+
@override
168+
final ScopeKind kind;
169+
@override
170+
final Map<String, TypeParameterBuilder>? _local;
171+
172+
final String _debugName;
173+
174+
LocalTypeParameterScope(
175+
{required this.kind,
176+
LocalScope? parent,
177+
Map<String, TypeParameterBuilder>? local,
178+
required String debugName})
179+
: _parent = parent,
180+
_local = local,
181+
_debugName = debugName;
182+
183+
@override
184+
String get classNameOrDebugName => _debugName;
185+
186+
@override
187+
String toString() =>
188+
"$runtimeType(${kind}, $classNameOrDebugName, ${_local?.keys})";
189+
}
190+
174191
final class FixedLocalScope extends BaseLocalScope
175192
with LookupScopeMixin, ImmutableLocalScopeMixin, LocalScopeMixin {
176193
@override

pkg/front_end/lib/src/kernel/body_builder.dart

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5085,41 +5085,49 @@ class BodyBuilder extends StackListenerImpl
50855085
void enterNominalVariablesScope(
50865086
List<NominalParameterBuilder>? nominalVariableBuilders) {
50875087
debugEvent("enterNominalVariableScope");
5088-
enterLocalScope(_localScope.createNestedScope(
5089-
debugName: "function-type scope", kind: ScopeKind.typeParameters));
5088+
Map<String, TypeParameterBuilder> typeParameters = {};
50905089
if (nominalVariableBuilders != null) {
50915090
for (NominalParameterBuilder builder in nominalVariableBuilders) {
50925091
if (builder.isWildcard) continue;
50935092
String name = builder.name;
5094-
Builder? existing = _localScope.lookupLocalVariable(name);
5093+
TypeParameterBuilder? existing = typeParameters[name];
50955094
if (existing == null) {
5096-
_localScope.addLocalVariable(name, builder);
5095+
typeParameters[name] = builder;
50975096
} else {
50985097
// Coverage-ignore-block(suite): Not run.
50995098
reportDuplicatedDeclaration(existing, name, builder.fileOffset);
51005099
}
51015100
}
51025101
}
5102+
enterLocalScope(new LocalTypeParameterScope(
5103+
local: typeParameters,
5104+
parent: _localScope,
5105+
debugName: "local function type parameter scope",
5106+
kind: ScopeKind.typeParameters));
51035107
}
51045108

51055109
void enterStructuralVariablesScope(
51065110
List<StructuralParameterBuilder>? structuralVariableBuilders) {
51075111
debugEvent("enterStructuralVariableScope");
5108-
enterLocalScope(_localScope.createNestedScope(
5109-
debugName: "function-type scope", kind: ScopeKind.typeParameters));
5112+
Map<String, TypeParameterBuilder> typeParameters = {};
51105113
if (structuralVariableBuilders != null) {
51115114
for (StructuralParameterBuilder builder in structuralVariableBuilders) {
51125115
if (builder.isWildcard) continue;
51135116
String name = builder.name;
5114-
Builder? existing = _localScope.lookupLocalVariable(name);
5117+
TypeParameterBuilder? existing = typeParameters[name];
51155118
if (existing == null) {
5116-
_localScope.addLocalVariable(name, builder);
5119+
typeParameters[name] = builder;
51175120
} else {
51185121
// Coverage-ignore-block(suite): Not run.
51195122
reportDuplicatedDeclaration(existing, name, builder.fileOffset);
51205123
}
51215124
}
51225125
}
5126+
enterLocalScope(new LocalTypeParameterScope(
5127+
local: typeParameters,
5128+
parent: _localScope,
5129+
debugName: "function-type scope",
5130+
kind: ScopeKind.typeParameters));
51235131
}
51245132

51255133
@override
@@ -7273,7 +7281,8 @@ class BodyBuilder extends StackListenerImpl
72737281
void handleNamedRecordField(Token colon) => handleNamedArgument(colon);
72747282

72757283
@override
7276-
void endFunctionName(Token beginToken, Token token) {
7284+
void endFunctionName(
7285+
Token beginToken, Token token, bool isFunctionExpression) {
72777286
debugEvent("FunctionName");
72787287
Identifier name = pop() as Identifier;
72797288
Token nameToken = name.token;
@@ -7290,20 +7299,24 @@ class BodyBuilder extends StackListenerImpl
72907299
isLocalFunction: true,
72917300
isWildcard: isWildcard)
72927301
..fileOffset = name.nameOffset;
7293-
// TODO(ahe): Why are we looking up in local scope, but declaring in parent
7294-
// scope?
7295-
Builder? existing = _localScope.lookupLocalVariable(name.name);
7296-
if (existing != null) {
7297-
// Coverage-ignore-block(suite): Not run.
7298-
reportDuplicatedDeclaration(existing, name.name, name.nameOffset);
7299-
}
73007302
push(new FunctionDeclarationImpl(
73017303
variable,
73027304
// The real function node is created later.
73037305
dummyFunctionNode)
73047306
..fileOffset = beginToken.charOffset);
73057307
if (!(libraryFeatures.wildcardVariables.isEnabled && variable.isWildcard)) {
7306-
declareVariable(variable, _localScopes.previous);
7308+
// The local scope stack contains a type parameter scope for the local
7309+
// function on top of the scope for the block in which the local function
7310+
// declaration occurs. So for a local function declaration, we add the
7311+
// declaration to the previous scope, i.e. the block scope.
7312+
//
7313+
// For a named function expression, a nested scope is created to hold the
7314+
// name, so that it doesn't pollute the block scope (the named function
7315+
// expression is erroneous and should introduce the name in the scope) and
7316+
// we therefore use the current scope in this case.
7317+
LocalScope scope =
7318+
isFunctionExpression ? _localScope : _localScopes.previous;
7319+
declareVariable(variable, scope);
73077320
}
73087321
}
73097322

pkg/front_end/lib/src/util/parser_ast_helper.dart

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,9 +1054,12 @@ abstract class AbstractParserAstListener implements Listener {
10541054
}
10551055

10561056
@override
1057-
void endFunctionName(Token beginToken, Token token) {
1057+
void endFunctionName(
1058+
Token beginToken, Token token, bool isFunctionExpression) {
10581059
FunctionNameEnd data = new FunctionNameEnd(ParserAstType.END,
1059-
beginToken: beginToken, token: token);
1060+
beginToken: beginToken,
1061+
token: token,
1062+
isFunctionExpression: isFunctionExpression);
10601063
seen(data);
10611064
}
10621065

@@ -5373,15 +5376,19 @@ class FunctionNameBegin extends ParserAstNode {
53735376
class FunctionNameEnd extends ParserAstNode {
53745377
final Token beginToken;
53755378
final Token token;
5379+
final bool isFunctionExpression;
53765380

53775381
FunctionNameEnd(ParserAstType type,
5378-
{required this.beginToken, required this.token})
5382+
{required this.beginToken,
5383+
required this.token,
5384+
required this.isFunctionExpression})
53795385
: super("FunctionName", type);
53805386

53815387
@override
53825388
Map<String, Object?> get deprecatedArguments => {
53835389
"beginToken": beginToken,
53845390
"token": token,
5391+
"isFunctionExpression": isFunctionExpression,
53855392
};
53865393

53875394
@override

pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ beginCompilationUnit(Future)
818818
handleType(await, null)
819819
beginFunctionName(foo)
820820
handleIdentifier(foo, localFunctionDeclaration)
821-
endFunctionName(await, ()
821+
endFunctionName(await, (, false)
822822
beginFormalParameters((, MemberKind.Local)
823823
beginMetadataStar(int)
824824
endMetadataStar(0)
@@ -855,7 +855,7 @@ beginCompilationUnit(Future)
855855
handleType(await, null)
856856
beginFunctionName(bar)
857857
handleIdentifier(bar, localFunctionDeclaration)
858-
endFunctionName(await, ()
858+
endFunctionName(await, (, false)
859859
beginFormalParameters((, MemberKind.Local)
860860
beginMetadataStar(await)
861861
endMetadataStar(0)

pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.intertwined.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2019,7 +2019,7 @@ parseUnit(Future)
20192019
listener: beginFunctionName(foo)
20202020
ensureIdentifier(await, localFunctionDeclaration)
20212021
listener: handleIdentifier(foo, localFunctionDeclaration)
2022-
listener: endFunctionName(await, ()
2022+
listener: endFunctionName(await, (, false)
20232023
parseFormalParametersRequiredOpt(foo, MemberKind.Local)
20242024
parseFormalParametersRest((, MemberKind.Local)
20252025
listener: beginFormalParameters((, MemberKind.Local)
@@ -2096,7 +2096,7 @@ parseUnit(Future)
20962096
listener: beginFunctionName(bar)
20972097
ensureIdentifier(await, localFunctionDeclaration)
20982098
listener: handleIdentifier(bar, localFunctionDeclaration)
2099-
listener: endFunctionName(await, ()
2099+
listener: endFunctionName(await, (, false)
21002100
parseFormalParametersRequiredOpt(bar, MemberKind.Local)
21012101
parseFormalParametersRest((, MemberKind.Local)
21022102
listener: beginFormalParameters((, MemberKind.Local)

0 commit comments

Comments
 (0)