Skip to content

Commit 01981b1

Browse files
jensjohaCommit Queue
authored andcommitted
[CFE] Expression compilation needs to use forEachLocalExtension to find unnamed extensions
Expression compilation doesn't normally allow non-identifier definitions, but does allow `#this` in extensions. We find if we're in an extension via a `.lookup` on the name, but that apparently doesn't work for unnamed extensions, they're filtered out in name_space_builder.dart: https://github.com/dart-lang/sdk/blob/67d39caa81551c009769febded1c2ac1a49a792c/pkg/front_end/lib/src/source/name_space_builder.dart#L315-L319 This in such cases use `.forEachLocalExtension` to find such extensions. Fixes #61294 Change-Id: I2af7bba732411c6288024365488e7fac88511c5e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/445220 Commit-Queue: Jens Johansen <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 42c5fe7 commit 01981b1

File tree

6 files changed

+111
-1
lines changed

6 files changed

+111
-1
lines changed

pkg/front_end/lib/src/api_prototype/lowering_predicates.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,13 @@ bool isExtensionThisName(String? name) {
692692
return name == syntheticThisName;
693693
}
694694

695+
// Coverage-ignore(suite): Not run.
696+
bool hasUnnamedExtensionNamePrefix(String? name) {
697+
if (name == null) return false;
698+
if (name.startsWith(NameScheme.unnamedExtensionNamePrefix)) return true;
699+
return false;
700+
}
701+
695702
// Coverage-ignore(suite): Not run.
696703
/// Return `true` if [node] is the synthetic parameter holding the `this` value
697704
/// in the encoding of extension type instance members and constructors.

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ import '../api_prototype/incremental_kernel_generator.dart'
6464
IncrementalKernelGenerator,
6565
isLegalIdentifier;
6666
import '../api_prototype/lowering_predicates.dart'
67-
show isExtensionThisName, syntheticThisName;
67+
show isExtensionThisName, syntheticThisName, hasUnnamedExtensionNamePrefix;
6868
import '../api_prototype/memory_file_system.dart' show MemoryFileSystem;
6969
import '../builder/builder.dart' show Builder;
7070
import '../builder/compilation_unit.dart'
@@ -1707,6 +1707,19 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
17071707
String afterDot = methodName.substring(indexOfDot + 1);
17081708
Builder? builder =
17091709
libraryBuilder.libraryNameSpace.lookup(beforeDot)?.getable;
1710+
1711+
if (builder == null && hasUnnamedExtensionNamePrefix(beforeDot)) {
1712+
// If the name looks like an unnamed extension, try to find if we
1713+
// can find such a builder.
1714+
ExtensionBuilder? foundExtensionBuilder;
1715+
libraryBuilder.libraryNameSpace
1716+
.forEachLocalExtension((ExtensionBuilder extension) {
1717+
if (extension.name == beforeDot) {
1718+
foundExtensionBuilder = extension;
1719+
}
1720+
});
1721+
builder = foundExtensionBuilder;
1722+
}
17101723
extensionName = beforeDot;
17111724
if (builder is ExtensionBuilder) {
17121725
extension = builder.extension;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
# for details. All rights reserved. Use of this source code is governed by a
3+
# BSD-style license that can be found in the LICENSE file.
4+
5+
# https://github.com/dart-lang/sdk/issues/61294
6+
7+
# Definition, offset, method etc extracted by starting the VM with
8+
# `-DDFE_VERBOSE=true`, e.g.
9+
# ```
10+
# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \
11+
# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart
12+
# ```
13+
# and then issuing the expression compilation.
14+
15+
sources: |
16+
import "dart:developer";
17+
18+
extension on String? {
19+
bool get isNullOrEmpty {
20+
var str = this;
21+
debugger();
22+
return str == null || str.isEmpty;
23+
}
24+
}
25+
26+
void main() {
27+
String? str = "hello";
28+
print(str.isNullOrEmpty);
29+
}
30+
31+
definitions: ["#this", "str"]
32+
definition_types: ["dart:core", "_OneByteString", "1", "0", "dart:core", "_OneByteString", "1", "0"]
33+
type_definitions: []
34+
type_bounds: []
35+
type_defaults: []
36+
method: "_extension#0.isNullOrEmpty"
37+
static: true
38+
offset: 100
39+
scriptUri: main.dart
40+
expression: |
41+
str
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Errors: {
2+
}
3+
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(lowered dart.core::_OneByteString #this, dart.core::_OneByteString str) → dynamic
4+
return str;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
# for details. All rights reserved. Use of this source code is governed by a
3+
# BSD-style license that can be found in the LICENSE file.
4+
5+
# https://github.com/dart-lang/sdk/issues/61294
6+
7+
# Definition, offset, method etc extracted by starting the VM with
8+
# `-DDFE_VERBOSE=true`, e.g.
9+
# ```
10+
# out/ReleaseX64/dart -DDFE_VERBOSE=true --enable-vm-service \
11+
# --disable-service-auth-codes --pause_isolates_on_start inputFile.dart
12+
# ```
13+
# and then issuing the expression compilation.
14+
15+
sources: |
16+
import "dart:developer";
17+
18+
extension Foo on String? {
19+
bool get isNullOrEmpty {
20+
var str = this;
21+
debugger();
22+
return str == null || str.isEmpty;
23+
}
24+
}
25+
26+
void main() {
27+
String? str = "hello";
28+
print(str.isNullOrEmpty);
29+
}
30+
31+
definitions: ["#this", "str"]
32+
definition_types: ["dart:core", "_OneByteString", "1", "0", "dart:core", "_OneByteString", "1", "0"]
33+
type_definitions: []
34+
type_bounds: []
35+
type_defaults: []
36+
method: "Foo.isNullOrEmpty"
37+
static: true
38+
offset: 104
39+
scriptUri: main.dart
40+
expression: |
41+
str
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Errors: {
2+
}
3+
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr(lowered dart.core::_OneByteString #this, dart.core::_OneByteString str) → dynamic
4+
return str;

0 commit comments

Comments
 (0)