diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart index 6e433798ea6b..9d5ee44e9956 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart @@ -845,7 +845,8 @@ class TypeInferrerImpl implements TypeInferrer { } if (includeExtensionMethods) { ObjectAccessTarget target = _findExtensionMember( - receiverBound, coreTypes.objectClass, name, fileOffset); + receiverBound, coreTypes.objectClass, name, fileOffset, + setter: setter); if (target != null) { return target; } diff --git a/pkg/front_end/testcases/nnbd/nullable_setter.dart b/pkg/front_end/testcases/nnbd/nullable_setter.dart new file mode 100644 index 000000000000..8e9d230fab22 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/nullable_setter.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2019, 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. + +class C { + String m = ""; + void set setter(String v) {} + void operator []=(int index, String value) {} +} + +extension on C? { + void set setter(String v) { + this?.m = v; + } + + void operator []=(int index, String value) { + this?.m = '$index$value'; + } +} + +main() { + C? c = new C(); + expect("", c?.m); + c.setter = "42"; + expect("42", c?.m); + c[42] = "87"; + expect("4287", c?.m); +} + +expect(expected, actual) { + if (expected != actual) throw 'Expected $expected, actual $actual'; +} diff --git a/pkg/front_end/testcases/nnbd/nullable_setter.dart.outline.expect b/pkg/front_end/testcases/nnbd/nullable_setter.dart.outline.expect new file mode 100644 index 000000000000..3f88610e5abb --- /dev/null +++ b/pkg/front_end/testcases/nnbd/nullable_setter.dart.outline.expect @@ -0,0 +1,25 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +class C extends core::Object { + field core::String m; + synthetic constructor •() → self::C + ; + set setter(core::String v) → void + ; + operator []=(core::int index, core::String value) → void + ; +} +extension _extension#0 on self::C? { + operator []= = self::_extension#0|[]=; + set setter = self::_extension#0|set#setter; +} +static method _extension#0|set#setter(final self::C? #this, core::String v) → void + ; +static method _extension#0|[]=(final self::C? #this, core::int index, core::String value) → void + ; +static method main() → dynamic + ; +static method expect(dynamic expected, dynamic actual) → dynamic + ; diff --git a/pkg/front_end/testcases/nnbd/nullable_setter.dart.strong.expect b/pkg/front_end/testcases/nnbd/nullable_setter.dart.strong.expect new file mode 100644 index 000000000000..d36785469a17 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/nullable_setter.dart.strong.expect @@ -0,0 +1,34 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +class C extends core::Object { + field core::String m = ""; + synthetic constructor •() → self::C + : super core::Object::•() + ; + set setter(core::String v) → void {} + operator []=(core::int index, core::String value) → void {} +} +extension _extension#0 on self::C? { + operator []= = self::_extension#0|[]=; + set setter = self::_extension#0|set#setter; +} +static method _extension#0|set#setter(final self::C? #this, core::String v) → void { + let final self::C? #t1 = #this in #t1.{core::Object::==}(null) ?{core::String?} null : #t1{self::C}.{self::C::m} = v; +} +static method _extension#0|[]=(final self::C? #this, core::int index, core::String value) → void { + let final self::C? #t2 = #this in #t2.{core::Object::==}(null) ?{core::String?} null : #t2{self::C}.{self::C::m} = "${index}${value}"; +} +static method main() → dynamic { + self::C? c = new self::C::•(); + self::expect("", let final self::C? #t3 = c in #t3.{core::Object::==}(null) ?{core::String?} null : #t3{self::C}.{self::C::m}); + self::_extension#0|set#setter(c, "42"); + self::expect("42", let final self::C? #t4 = c in #t4.{core::Object::==}(null) ?{core::String?} null : #t4{self::C}.{self::C::m}); + self::_extension#0|[]=(c, 42, "87"); + self::expect("4287", let final self::C? #t5 = c in #t5.{core::Object::==}(null) ?{core::String?} null : #t5{self::C}.{self::C::m}); +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!expected.{core::Object::==}(actual)) + throw "Expected ${expected}, actual ${actual}"; +} diff --git a/pkg/front_end/testcases/nnbd/nullable_setter.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/nullable_setter.dart.strong.transformed.expect new file mode 100644 index 000000000000..d36785469a17 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/nullable_setter.dart.strong.transformed.expect @@ -0,0 +1,34 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +class C extends core::Object { + field core::String m = ""; + synthetic constructor •() → self::C + : super core::Object::•() + ; + set setter(core::String v) → void {} + operator []=(core::int index, core::String value) → void {} +} +extension _extension#0 on self::C? { + operator []= = self::_extension#0|[]=; + set setter = self::_extension#0|set#setter; +} +static method _extension#0|set#setter(final self::C? #this, core::String v) → void { + let final self::C? #t1 = #this in #t1.{core::Object::==}(null) ?{core::String?} null : #t1{self::C}.{self::C::m} = v; +} +static method _extension#0|[]=(final self::C? #this, core::int index, core::String value) → void { + let final self::C? #t2 = #this in #t2.{core::Object::==}(null) ?{core::String?} null : #t2{self::C}.{self::C::m} = "${index}${value}"; +} +static method main() → dynamic { + self::C? c = new self::C::•(); + self::expect("", let final self::C? #t3 = c in #t3.{core::Object::==}(null) ?{core::String?} null : #t3{self::C}.{self::C::m}); + self::_extension#0|set#setter(c, "42"); + self::expect("42", let final self::C? #t4 = c in #t4.{core::Object::==}(null) ?{core::String?} null : #t4{self::C}.{self::C::m}); + self::_extension#0|[]=(c, 42, "87"); + self::expect("4287", let final self::C? #t5 = c in #t5.{core::Object::==}(null) ?{core::String?} null : #t5{self::C}.{self::C::m}); +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!expected.{core::Object::==}(actual)) + throw "Expected ${expected}, actual ${actual}"; +} diff --git a/pkg/front_end/testcases/nnbd/nullable_setter.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/nullable_setter.dart.textual_outline.expect new file mode 100644 index 000000000000..c1aeb83f8172 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/nullable_setter.dart.textual_outline.expect @@ -0,0 +1,10 @@ +class C { + String m = ""; + void set setter(String v) { } + void operator []=(int index, String value) { } +} +extension on ; +C; +? { void set setter(String v) { this?.m = v; } void operator []=(int index, String value) { this?.m = '$index$value'; } } +main() { } +expect(expected, actual) { } diff --git a/pkg/front_end/testcases/nnbd/nullable_setter.dart.weak.expect b/pkg/front_end/testcases/nnbd/nullable_setter.dart.weak.expect new file mode 100644 index 000000000000..d36785469a17 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/nullable_setter.dart.weak.expect @@ -0,0 +1,34 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +class C extends core::Object { + field core::String m = ""; + synthetic constructor •() → self::C + : super core::Object::•() + ; + set setter(core::String v) → void {} + operator []=(core::int index, core::String value) → void {} +} +extension _extension#0 on self::C? { + operator []= = self::_extension#0|[]=; + set setter = self::_extension#0|set#setter; +} +static method _extension#0|set#setter(final self::C? #this, core::String v) → void { + let final self::C? #t1 = #this in #t1.{core::Object::==}(null) ?{core::String?} null : #t1{self::C}.{self::C::m} = v; +} +static method _extension#0|[]=(final self::C? #this, core::int index, core::String value) → void { + let final self::C? #t2 = #this in #t2.{core::Object::==}(null) ?{core::String?} null : #t2{self::C}.{self::C::m} = "${index}${value}"; +} +static method main() → dynamic { + self::C? c = new self::C::•(); + self::expect("", let final self::C? #t3 = c in #t3.{core::Object::==}(null) ?{core::String?} null : #t3{self::C}.{self::C::m}); + self::_extension#0|set#setter(c, "42"); + self::expect("42", let final self::C? #t4 = c in #t4.{core::Object::==}(null) ?{core::String?} null : #t4{self::C}.{self::C::m}); + self::_extension#0|[]=(c, 42, "87"); + self::expect("4287", let final self::C? #t5 = c in #t5.{core::Object::==}(null) ?{core::String?} null : #t5{self::C}.{self::C::m}); +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!expected.{core::Object::==}(actual)) + throw "Expected ${expected}, actual ${actual}"; +} diff --git a/pkg/front_end/testcases/nnbd/nullable_setter.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/nullable_setter.dart.weak.transformed.expect new file mode 100644 index 000000000000..d36785469a17 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/nullable_setter.dart.weak.transformed.expect @@ -0,0 +1,34 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +class C extends core::Object { + field core::String m = ""; + synthetic constructor •() → self::C + : super core::Object::•() + ; + set setter(core::String v) → void {} + operator []=(core::int index, core::String value) → void {} +} +extension _extension#0 on self::C? { + operator []= = self::_extension#0|[]=; + set setter = self::_extension#0|set#setter; +} +static method _extension#0|set#setter(final self::C? #this, core::String v) → void { + let final self::C? #t1 = #this in #t1.{core::Object::==}(null) ?{core::String?} null : #t1{self::C}.{self::C::m} = v; +} +static method _extension#0|[]=(final self::C? #this, core::int index, core::String value) → void { + let final self::C? #t2 = #this in #t2.{core::Object::==}(null) ?{core::String?} null : #t2{self::C}.{self::C::m} = "${index}${value}"; +} +static method main() → dynamic { + self::C? c = new self::C::•(); + self::expect("", let final self::C? #t3 = c in #t3.{core::Object::==}(null) ?{core::String?} null : #t3{self::C}.{self::C::m}); + self::_extension#0|set#setter(c, "42"); + self::expect("42", let final self::C? #t4 = c in #t4.{core::Object::==}(null) ?{core::String?} null : #t4{self::C}.{self::C::m}); + self::_extension#0|[]=(c, 42, "87"); + self::expect("4287", let final self::C? #t5 = c in #t5.{core::Object::==}(null) ?{core::String?} null : #t5{self::C}.{self::C::m}); +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!expected.{core::Object::==}(actual)) + throw "Expected ${expected}, actual ${actual}"; +}