[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 <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
index 59d81bb..0c08b0f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
@@ -966,8 +966,9 @@
}
@override
- void endFunctionName(Token beginToken, Token token) {
- listener?.endFunctionName(beginToken, token);
+ void endFunctionName(
+ Token beginToken, Token token, bool isFunctionExpression) {
+ listener?.endFunctionName(beginToken, token, isFunctionExpression);
}
@override
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
index 187726a..08b9b65 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
@@ -812,7 +812,23 @@
void beginFunctionName(Token token) {}
- void endFunctionName(Token beginToken, Token token) {
+ /// The end of the function name in either a local function declaration, like
+ /// 'local' in:
+ ///
+ /// void m() {
+ /// void local() {}
+ /// }
+ ///
+ /// or an erroneous function expression, like 'local' in:
+ ///
+ /// void m() {
+ /// var f = void local() {};
+ /// }
+ ///
+ /// The boolean [isFunctionExpression] indicates that we are in the latter
+ /// case.
+ void endFunctionName(
+ Token beginToken, Token token, bool isFunctionExpression) {
logEvent("FunctionName");
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
index 7654aeb..814b3fc 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -5222,7 +5222,7 @@
reportRecoverableError(
beforeName.next!, codes.messageNamedFunctionExpression);
}
- listener.endFunctionName(begin, token);
+ listener.endFunctionName(begin, token, isFunctionExpression);
token = parseFormalParametersRequiredOpt(formals, MemberKind.Local);
token = parseInitializersOpt(token);
token = parseAsyncOptBody(
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 60032f2..19529e6 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2105,7 +2105,8 @@
}
@override
- void endFunctionName(Token beginToken, Token token) {
+ void endFunctionName(
+ Token beginToken, Token token, bool isFunctionExpression) {
debugEvent("FunctionName");
}
diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart
index a2f7b13..ecb79ff 100644
--- a/pkg/analyzer/test/generated/parser_fasta_listener.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart
@@ -981,9 +981,9 @@
}
@override
- void endFunctionName(Token beginToken, Token token) {
+ void endFunctionName(Token beginToken, Token token, bool isFunctionExpression) {
end('FunctionName');
- super.endFunctionName(beginToken, token);
+ super.endFunctionName(beginToken, token, isFunctionExpression);
}
@override
diff --git a/pkg/front_end/lib/src/base/local_scope.dart b/pkg/front_end/lib/src/base/local_scope.dart
index 8e0e30f..cca9d92 100644
--- a/pkg/front_end/lib/src/base/local_scope.dart
+++ b/pkg/front_end/lib/src/base/local_scope.dart
@@ -4,6 +4,7 @@
import '../builder/builder.dart';
import '../builder/declaration_builders.dart';
+import '../builder/variable_builder.dart';
import 'scope.dart';
abstract class LocalScope implements LookupScope {
@@ -27,9 +28,7 @@
/// If name was used previously in this scope, this method returns the read
/// offsets which can be used for reporting a compile-time error about
/// [name] being used before its declared.
- List<int>? declare(String name, Builder builder);
-
- void addLocalVariable(String name, Builder builder);
+ List<int>? declare(String name, VariableBuilder builder);
@override
Builder? lookupGetable(String name, int charOffset, Uri fileUri);
@@ -117,7 +116,7 @@
/// Names declared in this scope.
@override
- Map<String, Builder>? _local;
+ Map<String, VariableBuilder>? _local;
@override
Map<String, List<int>>? usedNames;
@@ -128,12 +127,7 @@
LocalScopeImpl(this._parent, this.kind, this.classNameOrDebugName);
@override
- void addLocalVariable(String name, Builder builder) {
- (_local ??= {})[name] = builder;
- }
-
- @override
- List<int>? declare(String name, Builder builder) {
+ List<int>? declare(String name, VariableBuilder builder) {
List<int>? previousOffsets = usedNames?[name];
if (previousOffsets != null && previousOffsets.isNotEmpty) {
return previousOffsets;
@@ -157,12 +151,7 @@
mixin ImmutableLocalScopeMixin implements LocalScope {
@override
- void addLocalVariable(String name, Builder builder) {
- throw new UnsupportedError('$runtimeType($kind).addLocalMember');
- }
-
- @override
- List<int>? declare(String name, Builder builder) {
+ List<int>? declare(String name, VariableBuilder builder) {
throw new UnsupportedError('$runtimeType($kind).declare');
}
@@ -171,6 +160,34 @@
Map<String, List<int>>? get usedNames => null;
}
+final class LocalTypeParameterScope extends BaseLocalScope
+ with LookupScopeMixin, ImmutableLocalScopeMixin, LocalScopeMixin {
+ @override
+ final LocalScope? _parent;
+ @override
+ final ScopeKind kind;
+ @override
+ final Map<String, TypeParameterBuilder>? _local;
+
+ final String _debugName;
+
+ LocalTypeParameterScope(
+ {required this.kind,
+ LocalScope? parent,
+ Map<String, TypeParameterBuilder>? local,
+ required String debugName})
+ : _parent = parent,
+ _local = local,
+ _debugName = debugName;
+
+ @override
+ String get classNameOrDebugName => _debugName;
+
+ @override
+ String toString() =>
+ "$runtimeType(${kind}, $classNameOrDebugName, ${_local?.keys})";
+}
+
final class FixedLocalScope extends BaseLocalScope
with LookupScopeMixin, ImmutableLocalScopeMixin, LocalScopeMixin {
@override
diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart
index 0b98cad..d3e9e98 100644
--- a/pkg/front_end/lib/src/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/kernel/body_builder.dart
@@ -5085,41 +5085,49 @@
void enterNominalVariablesScope(
List<NominalParameterBuilder>? nominalVariableBuilders) {
debugEvent("enterNominalVariableScope");
- enterLocalScope(_localScope.createNestedScope(
- debugName: "function-type scope", kind: ScopeKind.typeParameters));
+ Map<String, TypeParameterBuilder> typeParameters = {};
if (nominalVariableBuilders != null) {
for (NominalParameterBuilder builder in nominalVariableBuilders) {
if (builder.isWildcard) continue;
String name = builder.name;
- Builder? existing = _localScope.lookupLocalVariable(name);
+ TypeParameterBuilder? existing = typeParameters[name];
if (existing == null) {
- _localScope.addLocalVariable(name, builder);
+ typeParameters[name] = builder;
} else {
// Coverage-ignore-block(suite): Not run.
reportDuplicatedDeclaration(existing, name, builder.fileOffset);
}
}
}
+ enterLocalScope(new LocalTypeParameterScope(
+ local: typeParameters,
+ parent: _localScope,
+ debugName: "local function type parameter scope",
+ kind: ScopeKind.typeParameters));
}
void enterStructuralVariablesScope(
List<StructuralParameterBuilder>? structuralVariableBuilders) {
debugEvent("enterStructuralVariableScope");
- enterLocalScope(_localScope.createNestedScope(
- debugName: "function-type scope", kind: ScopeKind.typeParameters));
+ Map<String, TypeParameterBuilder> typeParameters = {};
if (structuralVariableBuilders != null) {
for (StructuralParameterBuilder builder in structuralVariableBuilders) {
if (builder.isWildcard) continue;
String name = builder.name;
- Builder? existing = _localScope.lookupLocalVariable(name);
+ TypeParameterBuilder? existing = typeParameters[name];
if (existing == null) {
- _localScope.addLocalVariable(name, builder);
+ typeParameters[name] = builder;
} else {
// Coverage-ignore-block(suite): Not run.
reportDuplicatedDeclaration(existing, name, builder.fileOffset);
}
}
}
+ enterLocalScope(new LocalTypeParameterScope(
+ local: typeParameters,
+ parent: _localScope,
+ debugName: "function-type scope",
+ kind: ScopeKind.typeParameters));
}
@override
@@ -7273,7 +7281,8 @@
void handleNamedRecordField(Token colon) => handleNamedArgument(colon);
@override
- void endFunctionName(Token beginToken, Token token) {
+ void endFunctionName(
+ Token beginToken, Token token, bool isFunctionExpression) {
debugEvent("FunctionName");
Identifier name = pop() as Identifier;
Token nameToken = name.token;
@@ -7290,20 +7299,24 @@
isLocalFunction: true,
isWildcard: isWildcard)
..fileOffset = name.nameOffset;
- // TODO(ahe): Why are we looking up in local scope, but declaring in parent
- // scope?
- Builder? existing = _localScope.lookupLocalVariable(name.name);
- if (existing != null) {
- // Coverage-ignore-block(suite): Not run.
- reportDuplicatedDeclaration(existing, name.name, name.nameOffset);
- }
push(new FunctionDeclarationImpl(
variable,
// The real function node is created later.
dummyFunctionNode)
..fileOffset = beginToken.charOffset);
if (!(libraryFeatures.wildcardVariables.isEnabled && variable.isWildcard)) {
- declareVariable(variable, _localScopes.previous);
+ // The local scope stack contains a type parameter scope for the local
+ // function on top of the scope for the block in which the local function
+ // declaration occurs. So for a local function declaration, we add the
+ // declaration to the previous scope, i.e. the block scope.
+ //
+ // For a named function expression, a nested scope is created to hold the
+ // name, so that it doesn't pollute the block scope (the named function
+ // expression is erroneous and should introduce the name in the scope) and
+ // we therefore use the current scope in this case.
+ LocalScope scope =
+ isFunctionExpression ? _localScope : _localScopes.previous;
+ declareVariable(variable, scope);
}
}
diff --git a/pkg/front_end/lib/src/util/parser_ast_helper.dart b/pkg/front_end/lib/src/util/parser_ast_helper.dart
index a5296cd..3f57e3e 100644
--- a/pkg/front_end/lib/src/util/parser_ast_helper.dart
+++ b/pkg/front_end/lib/src/util/parser_ast_helper.dart
@@ -1054,9 +1054,12 @@
}
@override
- void endFunctionName(Token beginToken, Token token) {
+ void endFunctionName(
+ Token beginToken, Token token, bool isFunctionExpression) {
FunctionNameEnd data = new FunctionNameEnd(ParserAstType.END,
- beginToken: beginToken, token: token);
+ beginToken: beginToken,
+ token: token,
+ isFunctionExpression: isFunctionExpression);
seen(data);
}
@@ -5373,15 +5376,19 @@
class FunctionNameEnd extends ParserAstNode {
final Token beginToken;
final Token token;
+ final bool isFunctionExpression;
FunctionNameEnd(ParserAstType type,
- {required this.beginToken, required this.token})
+ {required this.beginToken,
+ required this.token,
+ required this.isFunctionExpression})
: super("FunctionName", type);
@override
Map<String, Object?> get deprecatedArguments => {
"beginToken": beginToken,
"token": token,
+ "isFunctionExpression": isFunctionExpression,
};
@override
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.expect
index ae68e64..f431d52 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.expect
@@ -818,7 +818,7 @@
handleType(await, null)
beginFunctionName(foo)
handleIdentifier(foo, localFunctionDeclaration)
- endFunctionName(await, ()
+ endFunctionName(await, (, false)
beginFormalParameters((, MemberKind.Local)
beginMetadataStar(int)
endMetadataStar(0)
@@ -855,7 +855,7 @@
handleType(await, null)
beginFunctionName(bar)
handleIdentifier(bar, localFunctionDeclaration)
- endFunctionName(await, ()
+ endFunctionName(await, (, false)
beginFormalParameters((, MemberKind.Local)
beginMetadataStar(await)
endMetadataStar(0)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.intertwined.expect
index 9256ebc..f7ca385 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_49116.dart.intertwined.expect
@@ -2019,7 +2019,7 @@
listener: beginFunctionName(foo)
ensureIdentifier(await, localFunctionDeclaration)
listener: handleIdentifier(foo, localFunctionDeclaration)
- listener: endFunctionName(await, ()
+ listener: endFunctionName(await, (, false)
parseFormalParametersRequiredOpt(foo, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
@@ -2096,7 +2096,7 @@
listener: beginFunctionName(bar)
ensureIdentifier(await, localFunctionDeclaration)
listener: handleIdentifier(bar, localFunctionDeclaration)
- listener: endFunctionName(await, ()
+ listener: endFunctionName(await, (, false)
parseFormalParametersRequiredOpt(bar, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_49477.dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_49477.dart.expect
index 5b0b74c..7ca74e7 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_49477.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_49477.dart.expect
@@ -96,7 +96,7 @@
handleVoidKeyword(void)
beginFunctionName(writeMessage)
handleIdentifier(writeMessage, localFunctionDeclaration)
- endFunctionName(void, ()
+ endFunctionName(void, (, false)
beginFormalParameters((, MemberKind.Local)
beginMetadataStar(String)
endMetadataStar(0)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_49477.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/issue_49477.dart.intertwined.expect
index b6c710b..f88c864 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_49477.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_49477.dart.intertwined.expect
@@ -200,7 +200,7 @@
listener: beginFunctionName(writeMessage)
ensureIdentifier(void, localFunctionDeclaration)
listener: handleIdentifier(writeMessage, localFunctionDeclaration)
- listener: endFunctionName(void, ()
+ listener: endFunctionName(void, (, false)
parseFormalParametersRequiredOpt(writeMessage, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_49477_prime.dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_49477_prime.dart.expect
index 610bad0..7b4daa8 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_49477_prime.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_49477_prime.dart.expect
@@ -91,7 +91,7 @@
handleNoType(;)
beginFunctionName(getNumber)
handleIdentifier(getNumber, localFunctionDeclaration)
- endFunctionName(getNumber, ()
+ endFunctionName(getNumber, (, false)
beginFormalParameters((, MemberKind.Local)
endFormalParameters(0, (, ), MemberKind.Local)
handleNoInitializers()
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_49477_prime.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/issue_49477_prime.dart.intertwined.expect
index c9bd30b..ee4bb27 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_49477_prime.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_49477_prime.dart.intertwined.expect
@@ -196,7 +196,7 @@
listener: beginFunctionName(getNumber)
ensureIdentifier(;, localFunctionDeclaration)
listener: handleIdentifier(getNumber, localFunctionDeclaration)
- listener: endFunctionName(getNumber, ()
+ listener: endFunctionName(getNumber, (, false)
parseFormalParametersRequiredOpt(getNumber, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
diff --git a/pkg/front_end/parser_testcases/general/call_on_after_try_block2_prime.dart.expect b/pkg/front_end/parser_testcases/general/call_on_after_try_block2_prime.dart.expect
index 0aaa65f..dcd04bf 100644
--- a/pkg/front_end/parser_testcases/general/call_on_after_try_block2_prime.dart.expect
+++ b/pkg/front_end/parser_testcases/general/call_on_after_try_block2_prime.dart.expect
@@ -46,7 +46,7 @@
handleNoType(})
beginFunctionName(onX)
handleIdentifier(onX, localFunctionDeclaration)
- endFunctionName(onX, ()
+ endFunctionName(onX, (, false)
beginFormalParameters((, MemberKind.Local)
beginMetadataStar(e)
endMetadataStar(0)
diff --git a/pkg/front_end/parser_testcases/general/call_on_after_try_block2_prime.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/call_on_after_try_block2_prime.dart.intertwined.expect
index a4c0136..6ed3d52 100644
--- a/pkg/front_end/parser_testcases/general/call_on_after_try_block2_prime.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/general/call_on_after_try_block2_prime.dart.intertwined.expect
@@ -98,7 +98,7 @@
listener: beginFunctionName(onX)
ensureIdentifier(}, localFunctionDeclaration)
listener: handleIdentifier(onX, localFunctionDeclaration)
- listener: endFunctionName(onX, ()
+ listener: endFunctionName(onX, (, false)
parseFormalParametersRequiredOpt(onX, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
diff --git a/pkg/front_end/parser_testcases/general/function_declaration.dart.expect b/pkg/front_end/parser_testcases/general/function_declaration.dart.expect
index 0aba260..5c237ec 100644
--- a/pkg/front_end/parser_testcases/general/function_declaration.dart.expect
+++ b/pkg/front_end/parser_testcases/general/function_declaration.dart.expect
@@ -17,7 +17,7 @@
handleNoType({)
beginFunctionName(local)
handleIdentifier(local, localFunctionDeclaration)
- endFunctionName(local, ()
+ endFunctionName(local, (, false)
beginFormalParameters((, MemberKind.Local)
endFormalParameters(0, (, ), MemberKind.Local)
handleNoInitializers()
diff --git a/pkg/front_end/parser_testcases/general/function_declaration.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/function_declaration.dart.intertwined.expect
index abf2b04..401fa78 100644
--- a/pkg/front_end/parser_testcases/general/function_declaration.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/general/function_declaration.dart.intertwined.expect
@@ -40,7 +40,7 @@
listener: beginFunctionName(local)
ensureIdentifier({, localFunctionDeclaration)
listener: handleIdentifier(local, localFunctionDeclaration)
- listener: endFunctionName(local, ()
+ listener: endFunctionName(local, (, false)
parseFormalParametersRequiredOpt(local, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
diff --git a/pkg/front_end/parser_testcases/patterns/const_patterns.dart.expect b/pkg/front_end/parser_testcases/patterns/const_patterns.dart.expect
index 73ee566..1a50caa 100644
--- a/pkg/front_end/parser_testcases/patterns/const_patterns.dart.expect
+++ b/pkg/front_end/parser_testcases/patterns/const_patterns.dart.expect
@@ -931,7 +931,7 @@
beginFunctionName(fun)
handleIdentifier(fun, localFunctionDeclaration)
handleRecoverableError(NamedFunctionExpression, fun, fun)
- endFunctionName(void, ()
+ endFunctionName(void, (, true)
beginFormalParameters((, MemberKind.Local)
endFormalParameters(0, (, ), MemberKind.Local)
handleNoInitializers()
diff --git a/pkg/front_end/parser_testcases/patterns/const_patterns.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/const_patterns.dart.intertwined.expect
index 8d07e7e..0da519e 100644
--- a/pkg/front_end/parser_testcases/patterns/const_patterns.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/patterns/const_patterns.dart.intertwined.expect
@@ -1559,7 +1559,7 @@
listener: handleIdentifier(fun, localFunctionDeclaration)
reportRecoverableError(fun, NamedFunctionExpression)
listener: handleRecoverableError(NamedFunctionExpression, fun, fun)
- listener: endFunctionName(void, ()
+ listener: endFunctionName(void, (, true)
parseFormalParametersRequiredOpt(fun, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
diff --git a/pkg/front_end/parser_testcases/record/record_type_01.dart.expect b/pkg/front_end/parser_testcases/record/record_type_01.dart.expect
index 91a0150..b5b4017 100644
--- a/pkg/front_end/parser_testcases/record/record_type_01.dart.expect
+++ b/pkg/front_end/parser_testcases/record/record_type_01.dart.expect
@@ -444,7 +444,7 @@
handleType(int, null)
beginFunctionName(async)
handleIdentifier(async, localFunctionDeclaration)
- endFunctionName(int, ()
+ endFunctionName(int, (, false)
beginFormalParameters((, MemberKind.Local)
beginMetadataStar(int)
endMetadataStar(0)
@@ -502,7 +502,7 @@
endRecordType((, null, 2, false)
beginFunctionName(async)
handleIdentifier(async, localFunctionDeclaration)
- endFunctionName((, ()
+ endFunctionName((, (, false)
beginFormalParameters((, MemberKind.Local)
beginMetadataStar(int)
endMetadataStar(0)
@@ -560,7 +560,7 @@
endRecordType((, null, 2, false)
beginFunctionName(async)
handleIdentifier(async, localFunctionDeclaration)
- endFunctionName((, ()
+ endFunctionName((, (, false)
beginFormalParameters((, MemberKind.Local)
beginMetadataStar(int)
endMetadataStar(0)
diff --git a/pkg/front_end/parser_testcases/record/record_type_01.dart.intertwined.expect b/pkg/front_end/parser_testcases/record/record_type_01.dart.intertwined.expect
index fd46786..459c1bc 100644
--- a/pkg/front_end/parser_testcases/record/record_type_01.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/record/record_type_01.dart.intertwined.expect
@@ -886,7 +886,7 @@
ensureIdentifier(int, localFunctionDeclaration)
inPlainSync()
listener: handleIdentifier(async, localFunctionDeclaration)
- listener: endFunctionName(int, ()
+ listener: endFunctionName(int, (, false)
parseFormalParametersRequiredOpt(async, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
@@ -999,7 +999,7 @@
ensureIdentifier(), localFunctionDeclaration)
inPlainSync()
listener: handleIdentifier(async, localFunctionDeclaration)
- listener: endFunctionName((, ()
+ listener: endFunctionName((, (, false)
parseFormalParametersRequiredOpt(async, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
@@ -1112,7 +1112,7 @@
ensureIdentifier(), localFunctionDeclaration)
inPlainSync()
listener: handleIdentifier(async, localFunctionDeclaration)
- listener: endFunctionName((, ()
+ listener: endFunctionName((, (, false)
parseFormalParametersRequiredOpt(async, MemberKind.Local)
parseFormalParametersRest((, MemberKind.Local)
listener: beginFormalParameters((, MemberKind.Local)
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index da6075f..6f0f885 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -175,7 +175,7 @@
),
// 100.0%.
"package:front_end/src/base/local_scope.dart": (
- hitCount: 60,
+ hitCount: 59,
missCount: 0,
),
// 100.0%.
@@ -655,7 +655,7 @@
),
// 100.0%.
"package:front_end/src/kernel/body_builder.dart": (
- hitCount: 7247,
+ hitCount: 7243,
missCount: 0,
),
// 100.0%.
@@ -1001,7 +1001,7 @@
),
// 100.0%.
"package:front_end/src/source/type_parameter_scope_builder.dart": (
- hitCount: 1720,
+ hitCount: 1760,
missCount: 0,
),
// 100.0%.
@@ -1036,7 +1036,7 @@
),
// 100.0%.
"package:front_end/src/type_inference/inference_visitor.dart": (
- hitCount: 8291,
+ hitCount: 8312,
missCount: 0,
),
// 100.0%.
diff --git a/pkg/front_end/test/parser_test_listener.dart b/pkg/front_end/test/parser_test_listener.dart
index bc8e248..fbbb294 100644
--- a/pkg/front_end/test/parser_test_listener.dart
+++ b/pkg/front_end/test/parser_test_listener.dart
@@ -1151,11 +1151,13 @@
}
@override
- void endFunctionName(Token beginToken, Token token) {
+ void endFunctionName(
+ Token beginToken, Token token, bool isFunctionExpression) {
indent--;
seen(beginToken);
seen(token);
- doPrint('endFunctionName(' '$beginToken, ' '$token)');
+ doPrint(
+ 'endFunctionName(' '$beginToken, ' '$token, ' '$isFunctionExpression)');
}
@override
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 590c4b1..30957b0 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -1308,6 +1308,7 @@
pn
pointed
pointwise
+pollute
polluted
polymorphism
pool
diff --git a/pkg/front_end/testcases/general/duplicate_local_function.dart b/pkg/front_end/testcases/general/duplicate_local_function.dart
new file mode 100644
index 0000000..d409e89
--- /dev/null
+++ b/pkg/front_end/testcases/general/duplicate_local_function.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void test() {
+ void local() {}
+ void local() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.expect b/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.expect
new file mode 100644
index 0000000..ded6f82
--- /dev/null
+++ b/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.expect
@@ -0,0 +1,22 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/duplicate_local_function.dart:7:8: Error: 'local' is already declared in this scope.
+// void local() {}
+// ^^^^^
+// pkg/front_end/testcases/general/duplicate_local_function.dart:6:8: Context: Previous declaration of 'local'.
+// void local() {}
+// ^^^^^
+//
+import self as self;
+
+static method test() → void {
+ function local() → void {}
+ {
+ invalid-expression "pkg/front_end/testcases/general/duplicate_local_function.dart:7:8: Error: 'local' is already declared in this scope.
+ void local() {}
+ ^^^^^";
+ function local() → void {}
+ }
+}
diff --git a/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.modular.expect b/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.modular.expect
new file mode 100644
index 0000000..ded6f82
--- /dev/null
+++ b/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.modular.expect
@@ -0,0 +1,22 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/duplicate_local_function.dart:7:8: Error: 'local' is already declared in this scope.
+// void local() {}
+// ^^^^^
+// pkg/front_end/testcases/general/duplicate_local_function.dart:6:8: Context: Previous declaration of 'local'.
+// void local() {}
+// ^^^^^
+//
+import self as self;
+
+static method test() → void {
+ function local() → void {}
+ {
+ invalid-expression "pkg/front_end/testcases/general/duplicate_local_function.dart:7:8: Error: 'local' is already declared in this scope.
+ void local() {}
+ ^^^^^";
+ function local() → void {}
+ }
+}
diff --git a/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.outline.expect b/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.outline.expect
new file mode 100644
index 0000000..643a05a
--- /dev/null
+++ b/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method test() → void
+ ;
diff --git a/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.transformed.expect b/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.transformed.expect
new file mode 100644
index 0000000..ded6f82
--- /dev/null
+++ b/pkg/front_end/testcases/general/duplicate_local_function.dart.strong.transformed.expect
@@ -0,0 +1,22 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/duplicate_local_function.dart:7:8: Error: 'local' is already declared in this scope.
+// void local() {}
+// ^^^^^
+// pkg/front_end/testcases/general/duplicate_local_function.dart:6:8: Context: Previous declaration of 'local'.
+// void local() {}
+// ^^^^^
+//
+import self as self;
+
+static method test() → void {
+ function local() → void {}
+ {
+ invalid-expression "pkg/front_end/testcases/general/duplicate_local_function.dart:7:8: Error: 'local' is already declared in this scope.
+ void local() {}
+ ^^^^^";
+ function local() → void {}
+ }
+}
diff --git a/pkg/front_end/testcases/general/duplicate_local_function.dart.textual_outline.expect b/pkg/front_end/testcases/general/duplicate_local_function.dart.textual_outline.expect
new file mode 100644
index 0000000..7da700f
--- /dev/null
+++ b/pkg/front_end/testcases/general/duplicate_local_function.dart.textual_outline.expect
@@ -0,0 +1 @@
+void test() {}
diff --git a/pkg/front_end/testcases/general/duplicate_local_function.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/duplicate_local_function.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..7da700f
--- /dev/null
+++ b/pkg/front_end/testcases/general/duplicate_local_function.dart.textual_outline_modelled.expect
@@ -0,0 +1 @@
+void test() {}
diff --git a/pkg/front_end/testcases/general/named_function_scope.dart.strong.expect b/pkg/front_end/testcases/general/named_function_scope.dart.strong.expect
index 338b117..b92fa5d 100644
--- a/pkg/front_end/testcases/general/named_function_scope.dart.strong.expect
+++ b/pkg/front_end/testcases/general/named_function_scope.dart.strong.expect
@@ -42,13 +42,6 @@
// var x = T<T>() {};
// ^
//
-// pkg/front_end/testcases/general/named_function_scope.dart:52:13: Error: 'T' is already declared in this scope.
-// var x = T<T>() {};
-// ^
-// pkg/front_end/testcases/general/named_function_scope.dart:52:15: Context: Previous declaration of 'T'.
-// var x = T<T>() {};
-// ^
-//
// pkg/front_end/testcases/general/named_function_scope.dart:55:5: Error: Local variable 'T' can't be referenced before it is declared.
// T t;
// ^
@@ -155,12 +148,7 @@
}
{
invalid-type x = block {
- {
- invalid-expression "pkg/front_end/testcases/general/named_function_scope.dart:52:13: Error: 'T' is already declared in this scope.
- var x = T<T>() {};
- ^";
- function T<T extends core::Object? = dynamic>() → Null {}
- }
+ function T<T extends core::Object? = dynamic>() → Null {}
} =>invalid-expression "pkg/front_end/testcases/general/named_function_scope.dart:52:13: Error: A function expression can't have a name.
var x = T<T>() {};
^";
diff --git a/pkg/front_end/testcases/general/named_function_scope.dart.strong.modular.expect b/pkg/front_end/testcases/general/named_function_scope.dart.strong.modular.expect
index 338b117..b92fa5d 100644
--- a/pkg/front_end/testcases/general/named_function_scope.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/general/named_function_scope.dart.strong.modular.expect
@@ -42,13 +42,6 @@
// var x = T<T>() {};
// ^
//
-// pkg/front_end/testcases/general/named_function_scope.dart:52:13: Error: 'T' is already declared in this scope.
-// var x = T<T>() {};
-// ^
-// pkg/front_end/testcases/general/named_function_scope.dart:52:15: Context: Previous declaration of 'T'.
-// var x = T<T>() {};
-// ^
-//
// pkg/front_end/testcases/general/named_function_scope.dart:55:5: Error: Local variable 'T' can't be referenced before it is declared.
// T t;
// ^
@@ -155,12 +148,7 @@
}
{
invalid-type x = block {
- {
- invalid-expression "pkg/front_end/testcases/general/named_function_scope.dart:52:13: Error: 'T' is already declared in this scope.
- var x = T<T>() {};
- ^";
- function T<T extends core::Object? = dynamic>() → Null {}
- }
+ function T<T extends core::Object? = dynamic>() → Null {}
} =>invalid-expression "pkg/front_end/testcases/general/named_function_scope.dart:52:13: Error: A function expression can't have a name.
var x = T<T>() {};
^";
diff --git a/pkg/front_end/testcases/general/named_function_scope.dart.strong.transformed.expect b/pkg/front_end/testcases/general/named_function_scope.dart.strong.transformed.expect
index 338b117..b92fa5d 100644
--- a/pkg/front_end/testcases/general/named_function_scope.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/named_function_scope.dart.strong.transformed.expect
@@ -42,13 +42,6 @@
// var x = T<T>() {};
// ^
//
-// pkg/front_end/testcases/general/named_function_scope.dart:52:13: Error: 'T' is already declared in this scope.
-// var x = T<T>() {};
-// ^
-// pkg/front_end/testcases/general/named_function_scope.dart:52:15: Context: Previous declaration of 'T'.
-// var x = T<T>() {};
-// ^
-//
// pkg/front_end/testcases/general/named_function_scope.dart:55:5: Error: Local variable 'T' can't be referenced before it is declared.
// T t;
// ^
@@ -155,12 +148,7 @@
}
{
invalid-type x = block {
- {
- invalid-expression "pkg/front_end/testcases/general/named_function_scope.dart:52:13: Error: 'T' is already declared in this scope.
- var x = T<T>() {};
- ^";
- function T<T extends core::Object? = dynamic>() → Null {}
- }
+ function T<T extends core::Object? = dynamic>() → Null {}
} =>invalid-expression "pkg/front_end/testcases/general/named_function_scope.dart:52:13: Error: A function expression can't have a name.
var x = T<T>() {};
^";
diff --git a/pkg/front_end/testcases/general/recursive_named_function_expression.dart b/pkg/front_end/testcases/general/recursive_named_function_expression.dart
new file mode 100644
index 0000000..7f52f75
--- /dev/null
+++ b/pkg/front_end/testcases/general/recursive_named_function_expression.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void test() {
+ var f = void foo() {
+ foo();
+ };
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.expect b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.expect
new file mode 100644
index 0000000..0ab42b1
--- /dev/null
+++ b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.expect
@@ -0,0 +1,19 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/recursive_named_function_expression.dart:6:16: Error: A function expression can't have a name.
+// var f = void foo() {
+// ^^^
+//
+import self as self;
+
+static method test() → void {
+ invalid-type f = block {
+ function foo() → void {
+ foo(){() → void};
+ }
+ } =>invalid-expression "pkg/front_end/testcases/general/recursive_named_function_expression.dart:6:11: Error: A function expression can't have a name.
+ var f = void foo() {
+ ^";
+}
diff --git a/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.modular.expect b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.modular.expect
new file mode 100644
index 0000000..0ab42b1
--- /dev/null
+++ b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.modular.expect
@@ -0,0 +1,19 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/recursive_named_function_expression.dart:6:16: Error: A function expression can't have a name.
+// var f = void foo() {
+// ^^^
+//
+import self as self;
+
+static method test() → void {
+ invalid-type f = block {
+ function foo() → void {
+ foo(){() → void};
+ }
+ } =>invalid-expression "pkg/front_end/testcases/general/recursive_named_function_expression.dart:6:11: Error: A function expression can't have a name.
+ var f = void foo() {
+ ^";
+}
diff --git a/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.outline.expect b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.outline.expect
new file mode 100644
index 0000000..643a05a
--- /dev/null
+++ b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method test() → void
+ ;
diff --git a/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.transformed.expect b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.transformed.expect
new file mode 100644
index 0000000..0ab42b1
--- /dev/null
+++ b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.strong.transformed.expect
@@ -0,0 +1,19 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/recursive_named_function_expression.dart:6:16: Error: A function expression can't have a name.
+// var f = void foo() {
+// ^^^
+//
+import self as self;
+
+static method test() → void {
+ invalid-type f = block {
+ function foo() → void {
+ foo(){() → void};
+ }
+ } =>invalid-expression "pkg/front_end/testcases/general/recursive_named_function_expression.dart:6:11: Error: A function expression can't have a name.
+ var f = void foo() {
+ ^";
+}
diff --git a/pkg/front_end/testcases/general/recursive_named_function_expression.dart.textual_outline.expect b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.textual_outline.expect
new file mode 100644
index 0000000..7da700f
--- /dev/null
+++ b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.textual_outline.expect
@@ -0,0 +1 @@
+void test() {}
diff --git a/pkg/front_end/testcases/general/recursive_named_function_expression.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..7da700f
--- /dev/null
+++ b/pkg/front_end/testcases/general/recursive_named_function_expression.dart.textual_outline_modelled.expect
@@ -0,0 +1 @@
+void test() {}