Skip to content

Commit

Permalink
Version 3.7.0-215.0.dev
Browse files Browse the repository at this point in the history
Merge 33bdacc into dev
  • Loading branch information
Dart CI committed Dec 5, 2024
2 parents e7d679a + 33bdacc commit 4cdfbff
Show file tree
Hide file tree
Showing 394 changed files with 18,025 additions and 25,175 deletions.
432 changes: 197 additions & 235 deletions pkg/_fe_analyzer_shared/lib/src/experiments/flags.dart

Large diffs are not rendered by default.

7,954 changes: 4,282 additions & 3,672 deletions pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/_fe_analyzer_shared/lib/src/metadata/proto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ class GenericMixinProto extends Proto {
@override
Proto? resolve() {
List<TypeAnnotation>? newTypeArguments =
typeArguments.resolve((a) => a.resolve());
typeArguments.resolve((a) => a.resolve());
return newTypeArguments == null
? null
: new GenericMixinProto(reference, scope, newTypeArguments);
Expand Down
2 changes: 1 addition & 1 deletion pkg/_fe_analyzer_shared/lib/src/parser/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,4 @@ double doubleFromToken(Token token, {required bool hasSeparators}) {
text = stripSeparators(text);
}
return double.parse(text);
}
}
76 changes: 76 additions & 0 deletions pkg/analysis_server/test/analysis/get_navigation_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,82 @@ final b = new Foo.named(); // 0
expect(target.length, 5);
}

Future<void> test_constructorInvocation_insideNullAwareElement_inList() async {
addTestFile('''
class Foo {
Foo() {}
}
final foo = [?Foo()];
''');
await waitForTasksFinished();

await _getNavigation(search: 'Foo()];');
expect(regions, hasLength(1));
expect(regions.first.targets, hasLength(1));
var target = targets[regions.first.targets.first];
expect(target.kind, ElementKind.CONSTRUCTOR);
expect(target.offset, findOffset('Foo() {'));
expect(target.length, 3);
}

Future<void> test_constructorInvocation_insideNullAwareElement_inSet() async {
addTestFile('''
class Foo {
Foo() {}
}
final foo = {?Foo()};
''');
await waitForTasksFinished();

await _getNavigation(search: 'Foo()};');
expect(regions, hasLength(1));
expect(regions.first.targets, hasLength(1));
var target = targets[regions.first.targets.first];
expect(target.kind, ElementKind.CONSTRUCTOR);
expect(target.offset, findOffset('Foo() {'));
expect(target.length, 3);
}

Future<void> test_constructorInvocation_insideNullAwareKey_inMap() async {
addTestFile('''
class Foo {
Foo() {}
}
final foo = {?Foo(): "value"};
''');
await waitForTasksFinished();

await _getNavigation(search: 'Foo():');
expect(regions, hasLength(1));
expect(regions.first.targets, hasLength(1));
var target = targets[regions.first.targets.first];
expect(target.kind, ElementKind.CONSTRUCTOR);
expect(target.offset, findOffset('Foo() {'));
expect(target.length, 3);
}

Future<void> test_constructorInvocation_insideNullAwareValue_inMap() async {
addTestFile('''
class Foo {
Foo() {}
}
final foo = {"key": ?Foo()};
''');
await waitForTasksFinished();

await _getNavigation(search: 'Foo()};');
expect(regions, hasLength(1));
expect(regions.first.targets, hasLength(1));
var target = targets[regions.first.targets.first];
expect(target.kind, ElementKind.CONSTRUCTOR);
expect(target.offset, findOffset('Foo() {'));
expect(target.length, 3);
}

Future<void> test_field_underscore() async {
addTestFile('''
class C {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,46 @@ AAA aaa;
assertHasRegionTarget('AAA aaa;', 'AAA {}');
}

Future<void> test_afterAnalysis_inNullAwareElements_inList() async {
addTestFile('''
class AAA {}
final aaa = [?((AAA arg) => null)];
''');
await waitForTasksFinished();
await prepareNavigation();
assertHasRegionTarget('AAA arg', 'AAA {}');
}

Future<void> test_afterAnalysis_inNullAwareElements_inSet() async {
addTestFile('''
class AAA {}
final aaa = {?((AAA arg) => null)};
''');
await waitForTasksFinished();
await prepareNavigation();
assertHasRegionTarget('AAA arg', 'AAA {}');
}

Future<void> test_afterAnalysis_inNullAwareKey_inMap() async {
addTestFile('''
class AAA {}
final aaa = {?((AAA arg) => null): "value"};
''');
await waitForTasksFinished();
await prepareNavigation();
assertHasRegionTarget('AAA arg', 'AAA {}');
}

Future<void> test_afterAnalysis_inNullAwareValue_inMap() async {
addTestFile('''
class AAA {}
final aaa = {"key": ?((AAA arg) => null)};
''');
await waitForTasksFinished();
await prepareNavigation();
assertHasRegionTarget('AAA arg', 'AAA {}');
}

Future<void> test_annotation_generic_typeArguments_class() async {
addTestFile('''
class A<T> {
Expand Down
22 changes: 13 additions & 9 deletions pkg/dart2wasm/lib/dispatch_table.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,16 @@ class SelectorInfo {
int? offset;

/// The selector's member's name.
String get name => paramInfo.member!.name.text;
final String name;

SelectorInfo._(this.translator, this.id, this.callCount, this.paramInfo,
{required this.isSetter});
/// Whether the selector is for `Object.noSuchMethod`. We introduce instance
/// invocations of `noSuchMethod` in dynamic calls, so we always add
/// `noSuchMethod` overrides to the dispatch table.
final bool isNoSuchMethod;

SelectorInfo._(
this.translator, this.id, this.name, this.callCount, this.paramInfo,
{required this.isSetter, required this.isNoSuchMethod});

/// Compute the signature for the functions implementing members targeted by
/// this selector.
Expand Down Expand Up @@ -285,9 +291,10 @@ class DispatchTable {

final selector = _selectorInfo.putIfAbsent(
selectorId,
() => SelectorInfo._(translator, selectorId,
() => SelectorInfo._(translator, selectorId, member.name.text,
_selectorMetadata[selectorId].callCount, paramInfo,
isSetter: isSetter));
isSetter: isSetter,
isNoSuchMethod: member == translator.objectNoSuchMethod));
assert(selector.isSetter == isSetter);
selector.hasTearOffUses |= metadata.hasTearOffUses;
selector.hasNonThisUses |= metadata.hasNonThisUses;
Expand Down Expand Up @@ -452,10 +459,7 @@ class DispatchTable {
// Assign selector offsets

bool isUsedViaDispatchTableCall(SelectorInfo selector) {
// Special case for `objectNoSuchMethod`: we introduce instance
// invocations of `objectNoSuchMethod` in dynamic calls, so keep it alive
// even if there was no references to it from the Dart code.
if (selector.paramInfo.member! == translator.objectNoSuchMethod) {
if (selector.isNoSuchMethod) {
return true;
}
if (selector.callCount == 0) return false;
Expand Down
66 changes: 44 additions & 22 deletions pkg/dart2wasm/lib/param_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,22 @@ import 'reference_extensions.dart';
/// Information about optional parameters and their default values for a member
/// or a set of members belonging to the same override group.
class ParameterInfo {
final Member? member;
int typeParamCount = 0;
final int typeParamCount;

/// Default values of optional positonal parameters. `positional[i] == null`
/// means positional parameter `i` is not optional.
late final List<Constant?> positional;
final List<Constant?> positional;

/// Default values of named parameters. Similar to [positional], `null` means
/// the the parameter is not optional.
late final Map<String, Constant?> named;
final Map<String, Constant?> named;

// Do not access these until the info is complete.
final bool takesContextOrReceiver;

// Dispatch table builder updates `ParameterInfo`s, do not access late fields
// until the `ParameterInfo` is complete.
late final List<String> names = named.keys.toList()..sort();

late final Map<String, int> nameIndex = {
for (int i = 0; i < names.length; i++) names[i]: positional.length + i
};
Expand All @@ -45,47 +48,66 @@ class ParameterInfo {
}
}

ParameterInfo.fromMember(Reference target) : member = target.asMember {
FunctionNode? function = member!.function;
ParameterInfo._(this.takesContextOrReceiver, this.typeParamCount,
this.positional, this.named);

factory ParameterInfo.fromMember(Reference target) {
final member = target.asMember; // Constructor, Field, or Procedure
final function = member.function;

if (target.isTearOffReference) {
positional = [];
named = {};
} else if (function != null) {
typeParamCount = (member is Constructor
? member!.enclosingClass!.typeParameters
// Tear-off getters don't take type parameters even if the member is
// generic.
return ParameterInfo._(true, 0, [], {});
}

if (function != null) {
// Constructor, or static or instance method.
assert(member is Constructor || member is Procedure);

final typeParamCount = (member is Constructor
? member.enclosingClass.typeParameters
: function.typeParameters)
.length;
positional = List.generate(function.positionalParameters.length, (i) {

final positional =
List.generate(function.positionalParameters.length, (i) {
// A required parameter has no default value.
if (i < function.requiredParameterCount) return null;
return _defaultValue(function.positionalParameters[i]);
});
named = {

final named = {
for (VariableDeclaration param in function.namedParameters)
param.name!: _defaultValue(param)
};
} else {
// A setter parameter has no default value.
positional = [if (target.isSetter) null];
named = {};

return ParameterInfo._(
member.isInstanceMember, typeParamCount, positional, named);
}

// A setter or getter. A setter parameter has no default value.
assert(member is Field);
return ParameterInfo._(true, 0, [if (target.isSetter) null], {});
}

ParameterInfo.fromLocalFunction(FunctionNode function) : member = null {
typeParamCount = function.typeParameters.length;
positional = List.generate(function.positionalParameters.length, (i) {
factory ParameterInfo.fromLocalFunction(FunctionNode function) {
final typeParamCount = function.typeParameters.length;
final positional = List.generate(function.positionalParameters.length, (i) {
// A required parameter has no default value.
if (i < function.requiredParameterCount) return null;
return _defaultValue(function.positionalParameters[i]);
});
named = {
final named = {
for (VariableDeclaration param in function.namedParameters)
param.name!: _defaultValue(param)
};
return ParameterInfo._(true, typeParamCount, positional, named);
}

void merge(ParameterInfo other) {
assert(typeParamCount == other.typeParamCount);
assert(takesContextOrReceiver == other.takesContextOrReceiver);
for (int i = 0; i < other.positional.length; i++) {
if (i >= positional.length) {
positional.add(other.positional[i]);
Expand Down
30 changes: 7 additions & 23 deletions pkg/dart2wasm/lib/translator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -724,11 +724,6 @@ class Translator with KernelNodes {
ClosureImplementation getClosure(FunctionNode functionNode,
w.BaseFunction target, ParameterInfo paramInfo, String name) {
final targetModule = target.enclosingModule;
// The target function takes an extra initial parameter if it's a function
// expression / local function (which takes a context) or a tear-off of an
// instance method (which takes a receiver).
bool takesContextOrReceiver =
paramInfo.member == null || paramInfo.member!.isInstanceMember;

// Look up the closure representation for the signature.
int typeCount = functionNode.typeParameters.length;
Expand All @@ -741,7 +736,7 @@ class Translator with KernelNodes {
assert(positionalCount <= paramInfo.positional.length);
assert(names.length <= paramInfo.named.length);
assert(target.type.inputs.length ==
(takesContextOrReceiver ? 1 : 0) +
(paramInfo.takesContextOrReceiver ? 1 : 0) +
paramInfo.typeParamCount +
paramInfo.positional.length +
paramInfo.named.length);
Expand Down Expand Up @@ -805,7 +800,7 @@ class Translator with KernelNodes {
compilationQueue.add(CompilationTask(
trampoline,
_ClosureTrampolineGenerator(this, trampoline, target, typeCount,
posArgCount, argNames, paramInfo, takesContextOrReceiver)));
posArgCount, argNames, paramInfo)));
return trampoline;
}

Expand Down Expand Up @@ -1394,25 +1389,17 @@ class _ClosureTrampolineGenerator implements CodeGenerator {
final int posArgCount;
final List<String> argNames;
final ParameterInfo paramInfo;
final bool takesContextOrReceiver;

_ClosureTrampolineGenerator(
this.translator,
this.trampoline,
this.target,
this.typeCount,
this.posArgCount,
this.argNames,
this.paramInfo,
this.takesContextOrReceiver);

_ClosureTrampolineGenerator(this.translator, this.trampoline, this.target,
this.typeCount, this.posArgCount, this.argNames, this.paramInfo);

@override
void generate(w.InstructionsBuilder b, List<w.Local> paramLocals,
w.Label? returnLabel) {
assert(returnLabel == null);

int targetIndex = 0;
if (takesContextOrReceiver) {
if (paramInfo.takesContextOrReceiver) {
w.Local receiver = trampoline.locals[0];
b.local_get(receiver);
translator.convertType(
Expand Down Expand Up @@ -1478,9 +1465,6 @@ class _ClosureDynamicEntryGenerator implements CodeGenerator {

final b = function.body;

final bool takesContextOrReceiver =
paramInfo.member == null || paramInfo.member!.isInstanceMember;

final int typeCount = functionNode.typeParameters.length;

final closureLocal = function.locals[0];
Expand All @@ -1500,7 +1484,7 @@ class _ClosureDynamicEntryGenerator implements CodeGenerator {
int inputIdx = 0;

// Push context or receiver
if (takesContextOrReceiver) {
if (paramInfo.takesContextOrReceiver) {
final closureBaseType = w.RefType.def(
translator.closureLayouter.closureBaseStruct,
nullable: false);
Expand Down
Loading

0 comments on commit 4cdfbff

Please sign in to comment.