Skip to content

Commit 7cc9536

Browse files
jensjohaCommit Queue
authored andcommitted
[CFE] Fix setter from extension used in for loop
Change-Id: I6cfbd7b8c5d72ea508dcdb7f0b15ddaab1e0700d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/398062 Commit-Queue: Jens Johansen <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 3572482 commit 7cc9536

9 files changed

+153
-0
lines changed

pkg/front_end/lib/src/type_inference/for_in.dart

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:kernel/ast.dart';
77

88
import '../base/instrumentation.dart' show InstrumentationValueForMember;
99
import '../codes/cfe_codes.dart';
10+
import '../kernel/hierarchy/class_member.dart';
1011
import '../kernel/internal_ast.dart';
1112
import 'inference_results.dart';
1213
import 'inference_visitor.dart';
@@ -259,6 +260,57 @@ class StaticForInVariable implements ForInVariable {
259260
}
260261
}
261262

263+
class ExtensionSetForInVariable implements ForInVariable {
264+
final ExtensionSet extensionSet;
265+
DartType? setterType;
266+
267+
ExtensionSetForInVariable(this.extensionSet);
268+
269+
@override
270+
DartType computeElementType(InferenceVisitorBase visitor) {
271+
ExpressionInferenceResult receiverResult = visitor.inferExpression(
272+
extensionSet.receiver, const UnknownType(),
273+
isVoidAllowed: false);
274+
275+
List<DartType> extensionTypeArguments =
276+
visitor.computeExtensionTypeArgument(extensionSet.extension,
277+
extensionSet.explicitTypeArguments, receiverResult.inferredType,
278+
treeNodeForTesting: extensionSet);
279+
280+
DartType receiverType = visitor.getExtensionReceiverType(
281+
extensionSet.extension, extensionTypeArguments);
282+
283+
ObjectAccessTarget target = new ExtensionAccessTarget(
284+
receiverType,
285+
extensionSet.target,
286+
null,
287+
ClassMemberKind.Setter,
288+
extensionTypeArguments);
289+
290+
setterType = target.getSetterType(visitor);
291+
return setterType!;
292+
}
293+
294+
@override
295+
Expression inferAssignment(InferenceVisitorBase visitor, DartType rhsType) {
296+
assert(setterType != null);
297+
Expression rhs = visitor.ensureAssignable(
298+
setterType!, rhsType, extensionSet.value,
299+
errorTemplate: templateForInLoopElementTypeNotAssignable,
300+
nullabilityErrorTemplate:
301+
templateForInLoopElementTypeNotAssignableNullability,
302+
nullabilityPartErrorTemplate:
303+
templateForInLoopElementTypeNotAssignablePartNullability,
304+
isVoidAllowed: true);
305+
306+
extensionSet.value = rhs..parent = extensionSet;
307+
ExpressionInferenceResult result = visitor.inferExpression(
308+
extensionSet, const UnknownType(),
309+
isVoidAllowed: true);
310+
return result.expression;
311+
}
312+
}
313+
262314
class InvalidForInVariable implements ForInVariable {
263315
final Expression? expression;
264316

pkg/front_end/lib/src/type_inference/inference_visitor.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1690,6 +1690,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
16901690
return new SuperPropertyForInVariable(syntheticAssignment);
16911691
} else if (syntheticAssignment is StaticSet) {
16921692
return new StaticForInVariable(syntheticAssignment);
1693+
} else if (syntheticAssignment is ExtensionSet) {
1694+
return new ExtensionSetForInVariable(syntheticAssignment);
16931695
} else if (syntheticAssignment is InvalidExpression || hasProblem) {
16941696
return new InvalidForInVariable(syntheticAssignment);
16951697
} else {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2024, 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+
extension on String {
6+
set foo(int value) {}
7+
bar(List<int> input) {
8+
foo = 42;
9+
for (foo in input) {
10+
print("inside loop");
11+
}
12+
}
13+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
extension /* unnamed */ _extension#0 on core::String {
6+
method bar = self::_extension#0|bar;
7+
method tearoff bar = self::_extension#0|get#bar;
8+
set foo = self::_extension#0|set#foo;
9+
}
10+
static extension-member method _extension#0|set#foo(lowered final core::String #this, core::int value) → void {}
11+
static extension-member method _extension#0|bar(lowered final core::String #this, core::List<core::int> input) → dynamic {
12+
self::_extension#0|set#foo(#this, 42);
13+
for (final core::int #t1 in input) {
14+
self::_extension#0|set#foo(#this, #t1);
15+
core::print("inside loop");
16+
}
17+
}
18+
static extension-member method _extension#0|get#bar(lowered final core::String #this) → (core::List<core::int>) → dynamic
19+
return (core::List<core::int> input) → dynamic => self::_extension#0|bar(#this, input);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
extension /* unnamed */ _extension#0 on core::String {
6+
method bar = self::_extension#0|bar;
7+
method tearoff bar = self::_extension#0|get#bar;
8+
set foo = self::_extension#0|set#foo;
9+
}
10+
static extension-member method _extension#0|set#foo(lowered final core::String #this, core::int value) → void {}
11+
static extension-member method _extension#0|bar(lowered final core::String #this, core::List<core::int> input) → dynamic {
12+
self::_extension#0|set#foo(#this, 42);
13+
for (final core::int #t1 in input) {
14+
self::_extension#0|set#foo(#this, #t1);
15+
core::print("inside loop");
16+
}
17+
}
18+
static extension-member method _extension#0|get#bar(lowered final core::String #this) → (core::List<core::int>) → dynamic
19+
return (core::List<core::int> input) → dynamic => self::_extension#0|bar(#this, input);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
extension /* unnamed */ _extension#0 on core::String {
6+
method bar = self::_extension#0|bar;
7+
method tearoff bar = self::_extension#0|get#bar;
8+
set foo = self::_extension#0|set#foo;
9+
}
10+
static extension-member method _extension#0|set#foo(lowered final core::String #this, core::int value) → void
11+
;
12+
static extension-member method _extension#0|bar(lowered final core::String #this, core::List<core::int> input) → dynamic
13+
;
14+
static extension-member method _extension#0|get#bar(lowered final core::String #this) → (core::List<core::int>) → dynamic
15+
return (core::List<core::int> input) → dynamic => self::_extension#0|bar(#this, input);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
extension /* unnamed */ _extension#0 on core::String {
6+
method bar = self::_extension#0|bar;
7+
method tearoff bar = self::_extension#0|get#bar;
8+
set foo = self::_extension#0|set#foo;
9+
}
10+
static extension-member method _extension#0|set#foo(lowered final core::String #this, core::int value) → void {}
11+
static extension-member method _extension#0|bar(lowered final core::String #this, core::List<core::int> input) → dynamic {
12+
self::_extension#0|set#foo(#this, 42);
13+
{
14+
synthesized core::Iterator<core::int> :sync-for-iterator = input.{core::Iterable::iterator}{core::Iterator<core::int>};
15+
for (; :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
16+
final core::int #t1 = :sync-for-iterator.{core::Iterator::current}{core::int};
17+
{
18+
self::_extension#0|set#foo(#this, #t1);
19+
core::print("inside loop");
20+
}
21+
}
22+
}
23+
}
24+
static extension-member method _extension#0|get#bar(lowered final core::String #this) → (core::List<core::int>) → dynamic
25+
return (core::List<core::int> input) → dynamic => self::_extension#0|bar(#this, input);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
extension on String {
2+
set foo(int value) {}
3+
bar(List<int> input) {}
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
extension on String {
2+
bar(List<int> input) {}
3+
set foo(int value) {}
4+
}

0 commit comments

Comments
 (0)