mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 16:37:43 +00:00
[cfe] Handle implicit extension call()
Change-Id: Ib0aa04b7b00c54c21932040bd8912d95c138f62e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/118960 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Jens Johansen <jensj@google.com>
This commit is contained in:
parent
ee7aae43c0
commit
53564db036
|
@ -2554,29 +2554,33 @@ class ExplicitExtensionAccessGenerator extends Generator {
|
|||
return _makeInvalidRead();
|
||||
}
|
||||
|
||||
Generator _createInstanceAccess(Name name, {bool isNullAware}) {
|
||||
Builder getter = extensionBuilder.lookupLocalMember(name.name);
|
||||
Builder setter =
|
||||
extensionBuilder.lookupLocalMember(name.name, setter: true);
|
||||
if (getter == null && setter == null) {
|
||||
return new UnresolvedNameGenerator(_helper, token, name);
|
||||
}
|
||||
return new ExplicitExtensionInstanceAccessGenerator.fromBuilder(
|
||||
_helper,
|
||||
token,
|
||||
extensionBuilder.extension,
|
||||
getter,
|
||||
setter,
|
||||
receiver,
|
||||
explicitTypeArguments,
|
||||
extensionBuilder.typeParameters?.length ?? 0,
|
||||
isNullAware: isNullAware);
|
||||
}
|
||||
|
||||
/* Expression | Generator */ buildPropertyAccess(
|
||||
IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
|
||||
if (_helper.constantContext != ConstantContext.none) {
|
||||
_helper.addProblem(
|
||||
messageNotAConstantExpression, fileOffset, token.length);
|
||||
}
|
||||
Builder getter = extensionBuilder.lookupLocalMember(send.name.name);
|
||||
Builder setter =
|
||||
extensionBuilder.lookupLocalMember(send.name.name, setter: true);
|
||||
if (getter == null && setter == null) {
|
||||
return new UnresolvedNameGenerator(_helper, token, send.name);
|
||||
}
|
||||
Generator generator =
|
||||
new ExplicitExtensionInstanceAccessGenerator.fromBuilder(
|
||||
_helper,
|
||||
token,
|
||||
extensionBuilder.extension,
|
||||
getter,
|
||||
setter,
|
||||
receiver,
|
||||
explicitTypeArguments,
|
||||
extensionBuilder.typeParameters?.length ?? 0,
|
||||
isNullAware: isNullAware);
|
||||
_createInstanceAccess(send.name, isNullAware: isNullAware);
|
||||
if (send.arguments != null) {
|
||||
return generator.doInvocation(offsetForToken(send.token), send.arguments);
|
||||
} else {
|
||||
|
@ -2586,8 +2590,8 @@ class ExplicitExtensionAccessGenerator extends Generator {
|
|||
|
||||
@override
|
||||
doInvocation(int offset, Arguments arguments) {
|
||||
return unimplemented(
|
||||
"ExplicitExtensionAccessGenerator.doInvocation", fileOffset, _uri);
|
||||
Generator generator = _createInstanceAccess(callName, isNullAware: false);
|
||||
return generator.doInvocation(offset, arguments);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
27
pkg/front_end/testcases/extensions/extension_call.dart
Normal file
27
pkg/front_end/testcases/extensions/extension_call.dart
Normal file
|
@ -0,0 +1,27 @@
|
|||
// 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<T> {
|
||||
T method(T a) => a;
|
||||
}
|
||||
|
||||
extension Extension<T> on Class<T> {
|
||||
T call(T a) => method(a);
|
||||
}
|
||||
|
||||
main() {
|
||||
Class<int> c = new Class<int>();
|
||||
expect(42, c(42));
|
||||
expect(87, Extension(c)(87));
|
||||
expect(123, Extension<int>(c)(123));
|
||||
expect(42, c.call(42));
|
||||
expect(87, Extension(c).call(87));
|
||||
expect(123, Extension<int>(c).call(123));
|
||||
}
|
||||
|
||||
expect(expected, actual) {
|
||||
if (expected != actual) {
|
||||
throw 'Mismatch: expected=$expected, actual=$actual';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class Class<T extends core::Object* = dynamic> extends core::Object {
|
||||
synthetic constructor •() → self::Class<self::Class::T*>*
|
||||
;
|
||||
method method(generic-covariant-impl self::Class::T* a) → self::Class::T*
|
||||
;
|
||||
}
|
||||
extension Extension<T extends core::Object* = dynamic> on self::Class<T*>* {
|
||||
method call = self::Extension|call;
|
||||
tearoff call = self::Extension|get#call;
|
||||
}
|
||||
static method Extension|call<T extends core::Object* = dynamic>(final self::Class<self::Extension|call::T*>* #this, self::Extension|call::T* a) → self::Extension|call::T*
|
||||
;
|
||||
static method Extension|get#call<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#call::T*>* #this) → (self::Extension|get#call::T*) →* self::Extension|get#call::T*
|
||||
return (self::Extension|get#call::T* a) → self::Extension|get#call::T* => self::Extension|call<self::Extension|get#call::T*>(#this, a);
|
||||
static method main() → dynamic
|
||||
;
|
||||
static method expect(dynamic expected, dynamic actual) → dynamic
|
||||
;
|
|
@ -0,0 +1,33 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class Class<T extends core::Object* = dynamic> extends core::Object {
|
||||
synthetic constructor •() → self::Class<self::Class::T*>*
|
||||
: super core::Object::•()
|
||||
;
|
||||
method method(generic-covariant-impl self::Class::T* a) → self::Class::T*
|
||||
return a;
|
||||
}
|
||||
extension Extension<T extends core::Object* = dynamic> on self::Class<T*>* {
|
||||
method call = self::Extension|call;
|
||||
tearoff call = self::Extension|get#call;
|
||||
}
|
||||
static method Extension|call<T extends core::Object* = dynamic>(final self::Class<self::Extension|call::T*>* #this, self::Extension|call::T* a) → self::Extension|call::T*
|
||||
return #this.{self::Class::method}(a);
|
||||
static method Extension|get#call<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#call::T*>* #this) → (self::Extension|get#call::T*) →* self::Extension|get#call::T*
|
||||
return (self::Extension|get#call::T* a) → self::Extension|get#call::T* => self::Extension|call<self::Extension|get#call::T*>(#this, a);
|
||||
static method main() → dynamic {
|
||||
self::Class<core::int*>* c = new self::Class::•<core::int*>();
|
||||
self::expect(42, self::Extension|call<core::int*>(c, 42));
|
||||
self::expect(87, self::Extension|call<core::int*>(c, 87));
|
||||
self::expect(123, self::Extension|call<core::int*>(c, 123));
|
||||
self::expect(42, self::Extension|call<core::int*>(c, 42));
|
||||
self::expect(87, self::Extension|call<core::int*>(c, 87));
|
||||
self::expect(123, self::Extension|call<core::int*>(c, 123));
|
||||
}
|
||||
static method expect(dynamic expected, dynamic actual) → dynamic {
|
||||
if(!expected.{core::Object::==}(actual)) {
|
||||
throw "Mismatch: expected=${expected}, actual=${actual}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class Class<T extends core::Object* = dynamic> extends core::Object {
|
||||
synthetic constructor •() → self::Class<self::Class::T*>*
|
||||
: super core::Object::•()
|
||||
;
|
||||
method method(generic-covariant-impl self::Class::T* a) → self::Class::T*
|
||||
return a;
|
||||
}
|
||||
extension Extension<T extends core::Object* = dynamic> on self::Class<T*>* {
|
||||
method call = self::Extension|call;
|
||||
tearoff call = self::Extension|get#call;
|
||||
}
|
||||
static method Extension|call<T extends core::Object* = dynamic>(final self::Class<self::Extension|call::T*>* #this, self::Extension|call::T* a) → self::Extension|call::T*
|
||||
return #this.{self::Class::method}(a);
|
||||
static method Extension|get#call<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#call::T*>* #this) → (self::Extension|get#call::T*) →* self::Extension|get#call::T*
|
||||
return (self::Extension|get#call::T* a) → self::Extension|get#call::T* => self::Extension|call<self::Extension|get#call::T*>(#this, a);
|
||||
static method main() → dynamic {
|
||||
self::Class<core::int*>* c = new self::Class::•<core::int*>();
|
||||
self::expect(42, self::Extension|call<core::int*>(c, 42));
|
||||
self::expect(87, self::Extension|call<core::int*>(c, 87));
|
||||
self::expect(123, self::Extension|call<core::int*>(c, 123));
|
||||
self::expect(42, self::Extension|call<core::int*>(c, 42));
|
||||
self::expect(87, self::Extension|call<core::int*>(c, 87));
|
||||
self::expect(123, self::Extension|call<core::int*>(c, 123));
|
||||
}
|
||||
static method expect(dynamic expected, dynamic actual) → dynamic {
|
||||
if(!expected.{core::Object::==}(actual)) {
|
||||
throw "Mismatch: expected=${expected}, actual=${actual}";
|
||||
}
|
||||
}
|
|
@ -30,9 +30,9 @@ library;
|
|||
// Extension(c1).foo = null;
|
||||
// ^^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
|
||||
// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:17: Error: Method not found: 'foo'.
|
||||
// Extension(c1).foo();
|
||||
// ^^^
|
||||
// ^^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
|
||||
// Extension(c1).method();
|
||||
|
@ -180,9 +180,9 @@ Try changing the type of the parameter, or casting the argument to 'Class'.
|
|||
invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
|
||||
Extension(c1).foo = null;
|
||||
^^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
|
||||
invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:17: Error: Method not found: 'foo'.
|
||||
Extension(c1).foo();
|
||||
^^^";
|
||||
^^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
|
||||
Extension(c1).method();
|
||||
^";
|
||||
|
|
|
@ -30,9 +30,9 @@ library;
|
|||
// Extension(c1).foo = null;
|
||||
// ^^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
|
||||
// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:17: Error: Method not found: 'foo'.
|
||||
// Extension(c1).foo();
|
||||
// ^^^
|
||||
// ^^^
|
||||
//
|
||||
// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
|
||||
// Extension(c1).method();
|
||||
|
@ -180,9 +180,9 @@ Try changing the type of the parameter, or casting the argument to 'Class'.
|
|||
invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
|
||||
Extension(c1).foo = null;
|
||||
^^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
|
||||
invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:17: Error: Method not found: 'foo'.
|
||||
Extension(c1).foo();
|
||||
^^^";
|
||||
^^^";
|
||||
invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
|
||||
Extension(c1).method();
|
||||
^";
|
||||
|
|
|
@ -22,6 +22,7 @@ extensions/explicit_extension_inference: TextSerializationFailure
|
|||
extensions/explicit_generic_extension_access: TextSerializationFailure
|
||||
extensions/explicit_invalid_access: TextSerializationFailure
|
||||
extensions/explicit_this: TextSerializationFailure
|
||||
extensions/extension_call: TextSerializationFailure
|
||||
extensions/extension_methods: TextSerializationFailure
|
||||
extensions/extension_setter: TextSerializationFailure
|
||||
extensions/extension_setter_error: TypeCheckError
|
||||
|
|
Loading…
Reference in a new issue