mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:31:50 +00:00
Here's a start at exposing an API to address https://github.com/dart-lang/sdk/issues/31371.
There is no actual implementation here yet (that's your job :) ), but there is: - An external method in dart:_internal, extractTypeArguments(). - Empty patch methods for that for the VM, dart2js, and DDC. These need to have implementations filled in. - A "dart_internal" package to expose a subset of the API. It gives you: extractListTypeArgument() extractMapTypeArguments() We'll bring this into Google, but not publish it externally unless we find we really need to. - A test for the behavior. It probably has bugs since I can't run it. See: https://github.com/dart-lang/sdk/issues/31371 Change-Id: I7d9f9a3a36f8e8be106440375c80d584898c83cb Reviewed-on: https://dart-review.googlesource.com/26467 Commit-Queue: Bob Nystrom <rnystrom@google.com> Reviewed-by: Leaf Petersen <leafp@google.com> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Reviewed-by: Régis Crelier <regis@google.com> Reviewed-by: Siva Annamalai <asiva@google.com> Reviewed-by: Vijay Menon <vsm@google.com>
This commit is contained in:
parent
73ecd4c7b0
commit
03c8767f73
|
@ -29,6 +29,7 @@ convert:third_party/pkg/convert/lib
|
|||
crypto:third_party/pkg/crypto/lib
|
||||
csslib:third_party/pkg/csslib/lib
|
||||
dart2js_info:third_party/pkg/dart2js_info/lib
|
||||
dart_internal:pkg/dart_internal/lib
|
||||
dart_messages:pkg/dart_messages/lib
|
||||
dart_style:third_party/pkg_tested/dart_style/lib
|
||||
dartdoc:third_party/pkg/dartdoc/lib
|
||||
|
|
26
pkg/dart_internal/LICENSE
Normal file
26
pkg/dart_internal/LICENSE
Normal file
|
@ -0,0 +1,26 @@
|
|||
Copyright 2017, the Dart project authors. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
3
pkg/dart_internal/analysis_options.yaml
Normal file
3
pkg/dart_internal/analysis_options.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
43
pkg/dart_internal/lib/extract_type_arguments.dart
Normal file
43
pkg/dart_internal/lib/extract_type_arguments.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
// The actual functionality exposed by this package is implemented in
|
||||
// "dart:_internal" since it is specific to each platform's runtime
|
||||
// implementation. This package exists as a shell to expose that internal API
|
||||
// to outside code.
|
||||
//
|
||||
// Only this exact special file is allowed to import "dart:_internal" without
|
||||
// causing a compile error.
|
||||
import 'dart:_internal' as internal;
|
||||
|
||||
/// Given an [Iterable], invokes [extract], passing the [iterable]'s type
|
||||
/// argument as the type argument to the generic function.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```dart
|
||||
/// Object iterable = <int>[];
|
||||
/// print(extractIterableTypeArgument(iterable, <T>() => new Set<T>());
|
||||
/// // Prints "Instance of 'Set<int>'".
|
||||
/// ```
|
||||
Object extractIterableTypeArgument(
|
||||
Iterable iterable, Object Function<T>() extract) =>
|
||||
internal.extractTypeArguments<Iterable>(iterable, extract);
|
||||
|
||||
/// Given a [Map], invokes [extract], passing the [map]'s key and value type
|
||||
/// arguments as the type arguments to the generic function.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```dart
|
||||
/// class Two<A, B> {}
|
||||
///
|
||||
/// main() {
|
||||
/// Object map = <String, int>{};
|
||||
/// print(extractMapTypeArguments(map, <K, V>() => new Two<K, V>());
|
||||
/// // Prints "Instance of 'Two<String, int>'".
|
||||
/// }
|
||||
/// ```
|
||||
Object extractMapTypeArguments(Map map, Object Function<K, V>() extract) =>
|
||||
internal.extractTypeArguments<Map>(map, extract);
|
18
pkg/dart_internal/pubspec.yaml
Normal file
18
pkg/dart_internal/pubspec.yaml
Normal file
|
@ -0,0 +1,18 @@
|
|||
name: dart_internal
|
||||
version: 0.1.0-dev
|
||||
author: "Dart Team <misc@dartlang.org>"
|
||||
homepage: http://www.dartlang.org
|
||||
description: >
|
||||
This package is not intended for any external use. Basically, if you don't
|
||||
personally know exactly what it's for, you're probably not the intended user.
|
||||
|
||||
It contains functionality to enable some internal Google code to transition
|
||||
to strong mode before some anticipated language features are in place. In
|
||||
particular, it provides an API to solve the problem: "Given an object some
|
||||
generic type A, how do I construct an instance of generic type B with the
|
||||
same type argument(s)?"
|
||||
publish_to:
|
||||
# This package is not intended to be used externally (or, at least, not yet).
|
||||
none
|
||||
environment:
|
||||
sdk: ">=2.0.0 <2.0.0"
|
|
@ -47,6 +47,6 @@ List/*<E>*/ makeFixedListUnmodifiable/*<E>*/(List/*<E>*/ fixedLengthList) {
|
|||
return fixedLengthList;
|
||||
}
|
||||
|
||||
// TODO(vsm): Make this an @patch.
|
||||
Object extractTypeArguments<T>(T instance, Function f) =>
|
||||
dart.extractTypeArguments<T>(instance, f);
|
||||
@patch
|
||||
Object extractTypeArguments<T>(T instance, Function extract) =>
|
||||
dart.extractTypeArguments<T>(instance, extract);
|
||||
|
|
|
@ -24,6 +24,12 @@ List<T> makeListFixedLength<T>(List<T> growableList)
|
|||
List<T> makeFixedListUnmodifiable<T>(List<T> fixedLengthList)
|
||||
native "Internal_makeFixedListUnmodifiable";
|
||||
|
||||
@patch
|
||||
Object extractTypeArguments<T>(T instance, Function extract) {
|
||||
// TODO(31371): Implement this.
|
||||
throw new UnimplementedError();
|
||||
}
|
||||
|
||||
class VMLibraryHooks {
|
||||
// Example: "dart:isolate _Timer._factory"
|
||||
static var timerFactory;
|
||||
|
|
|
@ -45,3 +45,9 @@ List<T> makeListFixedLength<T>(List<T> growableList) {
|
|||
List<T> makeFixedListUnmodifiable<T>(List<T> fixedLengthList) {
|
||||
return JSArray.markUnmodifiableList(fixedLengthList);
|
||||
}
|
||||
|
||||
@patch
|
||||
Object extractTypeArguments<T>(T instance, Function extract) {
|
||||
// TODO(31371): Implement this.
|
||||
throw new UnimplementedError();
|
||||
}
|
||||
|
|
|
@ -96,3 +96,56 @@ int parseHexByte(String source, int index) {
|
|||
int digit2 = hexDigitValue(source.codeUnitAt(index + 1));
|
||||
return digit1 * 16 + digit2 - (digit2 & 256);
|
||||
}
|
||||
|
||||
/// Given an [instance] of some generic type [T], and [extract], a first-class
|
||||
/// generic function that takes the same number of type parameters as [T],
|
||||
/// invokes the function with the same type arguments that were passed to T
|
||||
/// when [instance] was constructed.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```dart
|
||||
/// class Two<A, B> {}
|
||||
///
|
||||
/// print(extractTypeArguments<List>(<int>[], <T>() => new Set<T>()));
|
||||
/// // Prints: Instance of 'Set<int>'.
|
||||
///
|
||||
/// print(extractTypeArguments<Map>(<String, bool>{},
|
||||
/// <T, S>() => new Two<T, S>));
|
||||
/// // Prints: Instance of 'Two<String, bool>'.
|
||||
/// ```
|
||||
///
|
||||
/// The type argument T is important to choose which specific type parameter
|
||||
/// list in [instance]'s type hierarchy is being extracted. Consider:
|
||||
///
|
||||
/// ```dart
|
||||
/// class A<T> {}
|
||||
/// class B<T> {}
|
||||
///
|
||||
/// class C implements A<int>, B<String> {}
|
||||
///
|
||||
/// main() {
|
||||
/// var c = new C();
|
||||
/// print(extractTypeArguments<A>(c, <T>() => <T>[]));
|
||||
/// // Prints: Instance of 'List<int>'.
|
||||
///
|
||||
/// print(extractTypeArguments<B>(c, <T>() => <T>[]));
|
||||
/// // Prints: Instance of 'List<String>'.
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A caller must not:
|
||||
///
|
||||
/// * Pass `null` for [instance].
|
||||
/// * Use a non-class type (i.e. a function type) for [T].
|
||||
/// * Use a non-generic type for [T].
|
||||
/// * Pass an instance of a generic type and a function that don't both take
|
||||
/// the same number of type arguments:
|
||||
///
|
||||
/// ```dart
|
||||
/// extractTypeArguments<List>(<int>[], <T, S>() => null);
|
||||
/// ```
|
||||
///
|
||||
/// See this issue for more context:
|
||||
/// https://github.com/dart-lang/sdk/issues/31371
|
||||
external Object extractTypeArguments<T>(T instance, Function extract);
|
||||
|
|
155
tests/language_2/extract_type_arguments_test.dart
Normal file
155
tests/language_2/extract_type_arguments_test.dart
Normal file
|
@ -0,0 +1,155 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
/// Tests the (probably temporary) API for extracting reified type arguments
|
||||
/// from an object.
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
// It's weird that a language test is testing code defined in a package. The
|
||||
// rationale for putting this test here is:
|
||||
//
|
||||
// * This package is special and "built-in" to Dart in that the various
|
||||
// compilers give it the special privilege of importing "dart:_internal"
|
||||
// without error.
|
||||
//
|
||||
// * Eventually, the API being tested here may be replaced with an actual
|
||||
// language feature, in which case this test will become an actual language
|
||||
// test.
|
||||
//
|
||||
// * Placing the test here ensures it is tested on all of the various platforms
|
||||
// and configurations where we need the API to work.
|
||||
import "package:dart_internal/extract_type_arguments.dart";
|
||||
|
||||
main() {
|
||||
testExtractIterableTypeArgument();
|
||||
testExtractMapTypeArguments();
|
||||
}
|
||||
|
||||
testExtractIterableTypeArgument() {
|
||||
Object object = <int>[];
|
||||
|
||||
// Invokes function with iterable's type argument.
|
||||
var called = false;
|
||||
extractIterableTypeArgument(object, <T>() {
|
||||
Expect.equals(T, int);
|
||||
called = true;
|
||||
});
|
||||
Expect.isTrue(called);
|
||||
|
||||
// Returns result of function.
|
||||
Object result = extractIterableTypeArgument(object, <T>() => new Set<T>());
|
||||
Expect.isTrue(result is Set<int>);
|
||||
Expect.isFalse(result is Set<bool>);
|
||||
|
||||
// Accepts user-defined implementations of Iterable.
|
||||
object = new CustomIterable();
|
||||
result = extractIterableTypeArgument(object, <T>() => new Set<T>());
|
||||
Expect.isTrue(result is Set<String>);
|
||||
Expect.isFalse(result is Set<bool>);
|
||||
}
|
||||
|
||||
testExtractMapTypeArguments() {
|
||||
Object object = <String, int>{};
|
||||
|
||||
// Invokes function with map's type arguments.
|
||||
var called = false;
|
||||
extractMapTypeArguments(object, <K, V>() {
|
||||
Expect.equals(K, String);
|
||||
Expect.equals(V, int);
|
||||
called = true;
|
||||
});
|
||||
Expect.isTrue(called);
|
||||
|
||||
// Returns result of function.
|
||||
Object result = extractMapTypeArguments(object, <K, V>() => new Two<K, V>());
|
||||
Expect.isTrue(result is Two<String, int>);
|
||||
Expect.isFalse(result is Two<int, String>);
|
||||
|
||||
// Accepts user-defined implementations of Map.
|
||||
object = new CustomMap();
|
||||
result = extractMapTypeArguments(object, <K, V>() => new Two<K, V>());
|
||||
Expect.isTrue(result is Two<int, bool>);
|
||||
Expect.isFalse(result is Two<bool, int>);
|
||||
|
||||
// Uses the type parameter order of Map, not any other type in the hierarchy.
|
||||
object = new FlippedMap<double, Null>();
|
||||
result = extractMapTypeArguments(object, <K, V>() => new Two<K, V>());
|
||||
// Order is reversed here:
|
||||
Expect.isTrue(result is Two<Null, double>);
|
||||
Expect.isFalse(result is Two<double, Null>);
|
||||
}
|
||||
|
||||
class Two<A, B> {}
|
||||
|
||||
// Implementing Iterable from scratch is kind of a chore, but ensures the API
|
||||
// works even if the class never bottoms out on a concrete class defining in a
|
||||
// "dart:" library.
|
||||
class CustomIterable implements Iterable<String> {
|
||||
bool any(Function test) => throw new UnimplementedError();
|
||||
bool contains(Object element) => throw new UnimplementedError();
|
||||
String elementAt(int index) => throw new UnimplementedError();
|
||||
bool every(Function test) => throw new UnimplementedError();
|
||||
Iterable<T> expand<T>(Function f) => throw new UnimplementedError();
|
||||
String get first => throw new UnimplementedError();
|
||||
String firstWhere(Function test, {Function orElse}) =>
|
||||
throw new UnimplementedError();
|
||||
T fold<T>(T initialValue, Function combine) => throw new UnimplementedError();
|
||||
void forEach(Function f) => throw new UnimplementedError();
|
||||
bool get isEmpty => throw new UnimplementedError();
|
||||
bool get isNotEmpty => throw new UnimplementedError();
|
||||
Iterator<String> get iterator => throw new UnimplementedError();
|
||||
String join([String separator = ""]) => throw new UnimplementedError();
|
||||
String get last => throw new UnimplementedError();
|
||||
String lastWhere(Function test, {Function orElse}) =>
|
||||
throw new UnimplementedError();
|
||||
int get length => throw new UnimplementedError();
|
||||
Iterable<T> map<T>(Function f) => throw new UnimplementedError();
|
||||
String reduce(Function combine) => throw new UnimplementedError();
|
||||
String get single => throw new UnimplementedError();
|
||||
String singleWhere(Function test) => throw new UnimplementedError();
|
||||
Iterable<String> skip(int count) => throw new UnimplementedError();
|
||||
Iterable<String> skipWhile(Function test) => throw new UnimplementedError();
|
||||
Iterable<String> take(int count) => throw new UnimplementedError();
|
||||
Iterable<String> takeWhile(Function test) => throw new UnimplementedError();
|
||||
List<String> toList({bool growable: true}) => throw new UnimplementedError();
|
||||
Set<String> toSet() => throw new UnimplementedError();
|
||||
Iterable<String> where(Function test) => throw new UnimplementedError();
|
||||
}
|
||||
|
||||
class CustomMap implements Map<int, bool> {
|
||||
bool operator [](Object key) => throw new UnimplementedError();
|
||||
void operator []=(int key, bool value) => throw new UnimplementedError();
|
||||
void addAll(Map<int, bool> other) => throw new UnimplementedError();
|
||||
void clear() => throw new UnimplementedError();
|
||||
bool containsKey(Object key) => throw new UnimplementedError();
|
||||
bool containsValue(Object value) => throw new UnimplementedError();
|
||||
void forEach(Function f) => throw new UnimplementedError();
|
||||
bool get isEmpty => throw new UnimplementedError();
|
||||
bool get isNotEmpty => throw new UnimplementedError();
|
||||
Iterable<int> get keys => throw new UnimplementedError();
|
||||
int get length => throw new UnimplementedError();
|
||||
bool putIfAbsent(int key, Function ifAbsent) =>
|
||||
throw new UnimplementedError();
|
||||
bool remove(Object key) => throw new UnimplementedError();
|
||||
Iterable<bool> get values => throw new UnimplementedError();
|
||||
}
|
||||
|
||||
// Note: Flips order of type parameters.
|
||||
class FlippedMap<V, K> implements Map<K, V> {
|
||||
V operator [](Object key) => throw new UnimplementedError();
|
||||
void operator []=(K key, V value) => throw new UnimplementedError();
|
||||
void addAll(Map<K, V> other) => throw new UnimplementedError();
|
||||
void clear() => throw new UnimplementedError();
|
||||
bool containsKey(Object key) => throw new UnimplementedError();
|
||||
bool containsValue(Object value) => throw new UnimplementedError();
|
||||
void forEach(Function f) => throw new UnimplementedError();
|
||||
bool get isEmpty => throw new UnimplementedError();
|
||||
bool get isNotEmpty => throw new UnimplementedError();
|
||||
Iterable<K> get keys => throw new UnimplementedError();
|
||||
int get length => throw new UnimplementedError();
|
||||
V putIfAbsent(K key, Function ifAbsent) => throw new UnimplementedError();
|
||||
V remove(Object key) => throw new UnimplementedError();
|
||||
Iterable<V> get values => throw new UnimplementedError();
|
||||
}
|
|
@ -142,6 +142,7 @@ error_stacktrace_test/00: MissingCompileTimeError
|
|||
example_constructor_test: RuntimeError
|
||||
external_test/21: CompileTimeError
|
||||
external_test/24: CompileTimeError
|
||||
extract_type_arguments_test: CompileTimeError # Issue 31371
|
||||
f_bounded_quantification_test/01: MissingCompileTimeError
|
||||
f_bounded_quantification_test/02: MissingCompileTimeError
|
||||
factory1_test/00: MissingCompileTimeError
|
||||
|
|
|
@ -286,6 +286,7 @@ emit_const_fields_test: CompileTimeError # Issue 31533
|
|||
export_ambiguous_main_test: MissingCompileTimeError
|
||||
external_test/21: CompileTimeError
|
||||
external_test/24: CompileTimeError
|
||||
extract_type_arguments_test: CompileTimeError # Issue 31371
|
||||
f_bounded_quantification_test/01: MissingCompileTimeError
|
||||
f_bounded_quantification_test/02: MissingCompileTimeError
|
||||
factory2_test/03: MissingCompileTimeError
|
||||
|
|
|
@ -473,6 +473,7 @@ example_constructor_test: Fail, OK
|
|||
external_test/10: MissingRuntimeError # KernelVM bug: Unbound external.
|
||||
external_test/13: MissingRuntimeError # KernelVM bug: Unbound external.
|
||||
external_test/20: MissingRuntimeError # KernelVM bug: Unbound external.
|
||||
extract_type_arguments_test: CompileTimeError # Issue 31371
|
||||
f_bounded_quantification_test/01: MissingCompileTimeError
|
||||
f_bounded_quantification_test/02: MissingCompileTimeError
|
||||
factory2_test/03: MissingCompileTimeError
|
||||
|
|
|
@ -311,6 +311,7 @@ empty_block_case_test: MissingCompileTimeError
|
|||
enum_private_test/02: MissingCompileTimeError
|
||||
error_stacktrace_test/00: MissingCompileTimeError
|
||||
export_ambiguous_main_test: MissingCompileTimeError
|
||||
extract_type_arguments_test: CompileTimeError # Issue 31371
|
||||
f_bounded_quantification_test/01: MissingCompileTimeError
|
||||
f_bounded_quantification_test/02: MissingCompileTimeError
|
||||
factory1_test/00: MissingCompileTimeError
|
||||
|
|
Loading…
Reference in a new issue