[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:
Johnni Winther 2019-09-26 10:36:51 +00:00 committed by commit-bot@chromium.org
parent ee7aae43c0
commit 53564db036
8 changed files with 146 additions and 26 deletions

View file

@ -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

View 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';
}
}

View file

@ -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
;

View file

@ -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}";
}
}

View file

@ -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}";
}
}

View file

@ -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();
^";

View file

@ -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();
^";

View file

@ -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