mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:27:39 +00:00
[cfe] Correctly resolve extension properties in face of getter/setter conflict
Change-Id: I0b818edb27de1b2cd1dcd2e046f42616cd7cb257 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/117729 Reviewed-by: Jens Johansen <jensj@google.com>
This commit is contained in:
parent
71896d5586
commit
2be1d090ca
|
@ -103,6 +103,9 @@ abstract class LibraryBuilder extends ModifierBuilder {
|
|||
/// Returns the [Library] built by this builder.
|
||||
Library get library;
|
||||
|
||||
/// Returns the import uri for the library.
|
||||
///
|
||||
/// This is the canonical uri for the library, for instance 'dart:core'.
|
||||
Uri get uri;
|
||||
|
||||
Iterator<Builder> get iterator {
|
||||
|
|
|
@ -717,13 +717,23 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
|||
}
|
||||
|
||||
if (target.isUnresolved && includeExtensionMethods) {
|
||||
Member otherMember =
|
||||
_getInterfaceMember(classNode, name, !setter, fileOffset);
|
||||
if (otherMember != null) {
|
||||
// If we're looking for `foo` and `foo=` can be found or vice-versa then
|
||||
// extension methods should not be found.
|
||||
return target;
|
||||
}
|
||||
|
||||
ExtensionAccessCandidate bestSoFar;
|
||||
List<ExtensionAccessCandidate> noneMoreSpecific = [];
|
||||
library.scope.forEachExtension((ExtensionBuilder extensionBuilder) {
|
||||
MemberBuilder memberBuilder =
|
||||
extensionBuilder.lookupLocalMember(name.name, setter: setter);
|
||||
if (memberBuilder != null && !memberBuilder.isStatic) {
|
||||
Extension extension = extensionBuilder.extension;
|
||||
MemberBuilder getterBuilder =
|
||||
extensionBuilder.lookupLocalMember(name.name, setter: false);
|
||||
MemberBuilder setterBuilder =
|
||||
extensionBuilder.lookupLocalMember(name.name, setter: true);
|
||||
if ((getterBuilder != null && !getterBuilder.isStatic) ||
|
||||
(setterBuilder != null && !setterBuilder.isStatic)) {
|
||||
DartType onType;
|
||||
DartType onTypeInstantiateToBounds;
|
||||
List<DartType> inferredTypeArguments;
|
||||
|
@ -762,15 +772,20 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
|||
}
|
||||
|
||||
if (typeSchemaEnvironment.isSubtypeOf(receiverType, onType)) {
|
||||
MemberBuilder memberBuilder =
|
||||
setter ? setterBuilder : getterBuilder;
|
||||
|
||||
ExtensionAccessCandidate candidate = new ExtensionAccessCandidate(
|
||||
extension,
|
||||
onType,
|
||||
onTypeInstantiateToBounds,
|
||||
new ObjectAccessTarget.extensionMember(
|
||||
memberBuilder.procedure,
|
||||
memberBuilder.extensionTearOff,
|
||||
memberBuilder.kind,
|
||||
inferredTypeArguments));
|
||||
memberBuilder != null
|
||||
? new ObjectAccessTarget.extensionMember(
|
||||
memberBuilder.procedure,
|
||||
memberBuilder.extensionTearOff,
|
||||
memberBuilder.kind,
|
||||
inferredTypeArguments)
|
||||
: const ObjectAccessTarget.missing(),
|
||||
isPlatform: extensionBuilder.library.uri.scheme == 'dart');
|
||||
if (noneMoreSpecific.isNotEmpty) {
|
||||
bool isMostSpecific = true;
|
||||
for (ExtensionAccessCandidate other in noneMoreSpecific) {
|
||||
|
@ -2839,11 +2854,11 @@ class ExtensionAccessCandidate {
|
|||
final bool isPlatform;
|
||||
final DartType onType;
|
||||
final DartType onTypeInstantiateToBounds;
|
||||
final ExtensionAccessTarget target;
|
||||
final ObjectAccessTarget target;
|
||||
|
||||
ExtensionAccessCandidate(Extension extension, this.onType,
|
||||
this.onTypeInstantiateToBounds, this.target)
|
||||
: isPlatform = extension.enclosingLibrary.importUri.scheme == 'dart';
|
||||
ExtensionAccessCandidate(
|
||||
this.onType, this.onTypeInstantiateToBounds, this.target,
|
||||
{this.isPlatform});
|
||||
|
||||
bool isMoreSpecificThan(TypeSchemaEnvironment typeSchemaEnvironment,
|
||||
ExtensionAccessCandidate other) {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// 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 Class {
|
||||
int get m1 => 0;
|
||||
void set m2(int x) {}
|
||||
}
|
||||
|
||||
extension Extension0 on Class {
|
||||
void set m1(int x) {}
|
||||
int get m2 => 0;
|
||||
void set m3(int x) {}
|
||||
int get m4 => 0;
|
||||
}
|
||||
|
||||
extension Extension1 on Class {
|
||||
int get m3 => 0;
|
||||
void set m4(int x) {}
|
||||
}
|
||||
|
||||
main() {
|
||||
var c = new Class();
|
||||
expect(0, c.m1);
|
||||
c.m2 = 2;
|
||||
}
|
||||
|
||||
errors() {
|
||||
var c = new Class();
|
||||
expect(0, c.m2);
|
||||
c.m1 = 2;
|
||||
c.m3;
|
||||
c.m3 = 2;
|
||||
c.m4;
|
||||
c.m4 = 2;
|
||||
}
|
||||
|
||||
expect(expected, actual) {
|
||||
if (expected != actual) {
|
||||
throw 'Mismatch: expected=$expected, actual=$actual';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class Class extends core::Object {
|
||||
synthetic constructor •() → self::Class*
|
||||
;
|
||||
get m1() → core::int*
|
||||
;
|
||||
set m2(core::int* x) → void
|
||||
;
|
||||
}
|
||||
extension Extension0 on self::Class* {
|
||||
get m2 = self::Extension0|get#m2;
|
||||
get m4 = self::Extension0|get#m4;
|
||||
set m1 = self::Extension0|set#m1;
|
||||
set m3 = self::Extension0|set#m3;
|
||||
}
|
||||
extension Extension1 on self::Class* {
|
||||
get m3 = self::Extension1|get#m3;
|
||||
set m4 = self::Extension1|set#m4;
|
||||
}
|
||||
static method Extension0|set#m1(final self::Class* #this, core::int* x) → void
|
||||
;
|
||||
static method Extension0|get#m2(final self::Class* #this) → core::int*
|
||||
;
|
||||
static method Extension0|set#m3(final self::Class* #this, core::int* x) → void
|
||||
;
|
||||
static method Extension0|get#m4(final self::Class* #this) → core::int*
|
||||
;
|
||||
static method Extension1|get#m3(final self::Class* #this) → core::int*
|
||||
;
|
||||
static method Extension1|set#m4(final self::Class* #this, core::int* x) → void
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
||||
static method errors() → dynamic
|
||||
;
|
||||
static method expect(dynamic expected, dynamic actual) → dynamic
|
||||
;
|
|
@ -0,0 +1,122 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:30:15: Error: The getter 'm2' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing getter, or defining a getter or field named 'm2'.
|
||||
// expect(0, c.m2);
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:31:5: Error: The setter 'm1' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing setter, or defining a setter or field named 'm1'.
|
||||
// c.m1 = 2;
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:32:5: Error: The getter 'm3' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing getter, or defining a getter or field named 'm3'.
|
||||
// c.m3;
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:33:5: Error: The setter 'm3' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing setter, or defining a setter or field named 'm3'.
|
||||
// c.m3 = 2;
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:34:5: Error: The getter 'm4' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing getter, or defining a getter or field named 'm4'.
|
||||
// c.m4;
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:35:5: Error: The setter 'm4' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing setter, or defining a setter or field named 'm4'.
|
||||
// c.m4 = 2;
|
||||
// ^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class Class extends core::Object {
|
||||
synthetic constructor •() → self::Class*
|
||||
: super core::Object::•()
|
||||
;
|
||||
get m1() → core::int*
|
||||
return 0;
|
||||
set m2(core::int* x) → void {}
|
||||
}
|
||||
extension Extension0 on self::Class* {
|
||||
get m2 = self::Extension0|get#m2;
|
||||
get m4 = self::Extension0|get#m4;
|
||||
set m1 = self::Extension0|set#m1;
|
||||
set m3 = self::Extension0|set#m3;
|
||||
}
|
||||
extension Extension1 on self::Class* {
|
||||
get m3 = self::Extension1|get#m3;
|
||||
set m4 = self::Extension1|set#m4;
|
||||
}
|
||||
static method Extension0|set#m1(final self::Class* #this, core::int* x) → core::int* {
|
||||
final core::int* #t1 = x;
|
||||
return #t1;
|
||||
}
|
||||
static method Extension0|get#m2(final self::Class* #this) → core::int*
|
||||
return 0;
|
||||
static method Extension0|set#m3(final self::Class* #this, core::int* x) → core::int* {
|
||||
final core::int* #t2 = x;
|
||||
return #t2;
|
||||
}
|
||||
static method Extension0|get#m4(final self::Class* #this) → core::int*
|
||||
return 0;
|
||||
static method Extension1|get#m3(final self::Class* #this) → core::int*
|
||||
return 0;
|
||||
static method Extension1|set#m4(final self::Class* #this, core::int* x) → core::int* {
|
||||
final core::int* #t3 = x;
|
||||
return #t3;
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::Class* c = new self::Class::•();
|
||||
self::expect(0, c.{self::Class::m1});
|
||||
c.{self::Class::m2} = 2;
|
||||
}
|
||||
static method errors() → dynamic {
|
||||
self::Class* c = new self::Class::•();
|
||||
self::expect(0, invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:30:15: Error: The getter 'm2' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing getter, or defining a getter or field named 'm2'.
|
||||
expect(0, c.m2);
|
||||
^^");
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:31:5: Error: The setter 'm1' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing setter, or defining a setter or field named 'm1'.
|
||||
c.m1 = 2;
|
||||
^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:32:5: Error: The getter 'm3' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing getter, or defining a getter or field named 'm3'.
|
||||
c.m3;
|
||||
^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:33:5: Error: The setter 'm3' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing setter, or defining a setter or field named 'm3'.
|
||||
c.m3 = 2;
|
||||
^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:34:5: Error: The getter 'm4' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing getter, or defining a getter or field named 'm4'.
|
||||
c.m4;
|
||||
^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:35:5: Error: The setter 'm4' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing setter, or defining a setter or field named 'm4'.
|
||||
c.m4 = 2;
|
||||
^^";
|
||||
}
|
||||
static method expect(dynamic expected, dynamic actual) → dynamic {
|
||||
if(!expected.{core::Object::==}(actual)) {
|
||||
throw "Mismatch: expected=${expected}, actual=${actual}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
library;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:30:15: Error: The getter 'm2' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing getter, or defining a getter or field named 'm2'.
|
||||
// expect(0, c.m2);
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:31:5: Error: The setter 'm1' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing setter, or defining a setter or field named 'm1'.
|
||||
// c.m1 = 2;
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:32:5: Error: The getter 'm3' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing getter, or defining a getter or field named 'm3'.
|
||||
// c.m3;
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:33:5: Error: The setter 'm3' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing setter, or defining a setter or field named 'm3'.
|
||||
// c.m3 = 2;
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:34:5: Error: The getter 'm4' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing getter, or defining a getter or field named 'm4'.
|
||||
// c.m4;
|
||||
// ^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/getter_setter_conflict.dart:35:5: Error: The setter 'm4' isn't defined for the class 'Class'.
|
||||
// - 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
// Try correcting the name to the name of an existing setter, or defining a setter or field named 'm4'.
|
||||
// c.m4 = 2;
|
||||
// ^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class Class extends core::Object {
|
||||
synthetic constructor •() → self::Class*
|
||||
: super core::Object::•()
|
||||
;
|
||||
get m1() → core::int*
|
||||
return 0;
|
||||
set m2(core::int* x) → void {}
|
||||
}
|
||||
extension Extension0 on self::Class* {
|
||||
get m2 = self::Extension0|get#m2;
|
||||
get m4 = self::Extension0|get#m4;
|
||||
set m1 = self::Extension0|set#m1;
|
||||
set m3 = self::Extension0|set#m3;
|
||||
}
|
||||
extension Extension1 on self::Class* {
|
||||
get m3 = self::Extension1|get#m3;
|
||||
set m4 = self::Extension1|set#m4;
|
||||
}
|
||||
static method Extension0|set#m1(final self::Class* #this, core::int* x) → core::int* {
|
||||
final core::int* #t1 = x;
|
||||
return #t1;
|
||||
}
|
||||
static method Extension0|get#m2(final self::Class* #this) → core::int*
|
||||
return 0;
|
||||
static method Extension0|set#m3(final self::Class* #this, core::int* x) → core::int* {
|
||||
final core::int* #t2 = x;
|
||||
return #t2;
|
||||
}
|
||||
static method Extension0|get#m4(final self::Class* #this) → core::int*
|
||||
return 0;
|
||||
static method Extension1|get#m3(final self::Class* #this) → core::int*
|
||||
return 0;
|
||||
static method Extension1|set#m4(final self::Class* #this, core::int* x) → core::int* {
|
||||
final core::int* #t3 = x;
|
||||
return #t3;
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::Class* c = new self::Class::•();
|
||||
self::expect(0, c.{self::Class::m1});
|
||||
c.{self::Class::m2} = 2;
|
||||
}
|
||||
static method errors() → dynamic {
|
||||
self::Class* c = new self::Class::•();
|
||||
self::expect(0, invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:30:15: Error: The getter 'm2' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing getter, or defining a getter or field named 'm2'.
|
||||
expect(0, c.m2);
|
||||
^^");
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:31:5: Error: The setter 'm1' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing setter, or defining a setter or field named 'm1'.
|
||||
c.m1 = 2;
|
||||
^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:32:5: Error: The getter 'm3' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing getter, or defining a getter or field named 'm3'.
|
||||
c.m3;
|
||||
^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:33:5: Error: The setter 'm3' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing setter, or defining a setter or field named 'm3'.
|
||||
c.m3 = 2;
|
||||
^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:34:5: Error: The getter 'm4' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing getter, or defining a getter or field named 'm4'.
|
||||
c.m4;
|
||||
^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/getter_setter_conflict.dart:35:5: Error: The setter 'm4' isn't defined for the class 'Class'.
|
||||
- 'Class' is from 'pkg/front_end/testcases/extensions/getter_setter_conflict.dart'.
|
||||
Try correcting the name to the name of an existing setter, or defining a setter or field named 'm4'.
|
||||
c.m4 = 2;
|
||||
^^";
|
||||
}
|
||||
static method expect(dynamic expected, dynamic actual) → dynamic {
|
||||
if(!expected.{core::Object::==}(actual)) {
|
||||
throw "Mismatch: expected=${expected}, actual=${actual}";
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ extensions/explicit_extension_inference: TextSerializationFailure
|
|||
extensions/explicit_generic_extension_access: TextSerializationFailure
|
||||
extensions/explicit_this: TextSerializationFailure
|
||||
extensions/extension_methods: TextSerializationFailure
|
||||
extensions/getter_setter_conflict: TextSerializationFailure
|
||||
extensions/implicit_extension_inference: TextSerializationFailure
|
||||
extensions/implicit_this: TextSerializationFailure
|
||||
extensions/index: TextSerializationFailure
|
||||
|
|
Loading…
Reference in a new issue