Revision of "Adjusts dart2js backend to handle method type arguments"
Adjusted version of CL https://codereview.chromium.org/1976213002/, only changed by adding entries in status files for the test 'tests/language/generic_methods_type_expression_test.dart'. Review URL: https://codereview.chromium.org/2001393003 .
This commit is contained in:
@@ -52,6 +52,17 @@ class Flags {
|
||||
static const String conditionalDirectives = '--conditional-directives';
|
||||
|
||||
// Experimental flags.
|
||||
|
||||
// Considerations about this feature (esp. locations where generalizations
|
||||
// or changes are required for full support of generic methods) are marked
|
||||
// with 'GENERIC_METHODS'. The approach taken is to parse generic methods,
|
||||
// introduce AST nodes for them, generate corresponding types (such that
|
||||
// front end treatment is consistent with the code that programmers wrote),
|
||||
// but considering all method type variables to have bound `dynamic` no
|
||||
// matter which bound they have syntactically (such that their value as types
|
||||
// is unchecked), and then replacing method type variables by a `DynamicType`
|
||||
// (such that the backend does not need to take method type arguments into
|
||||
// account).
|
||||
static const String genericMethodSyntax = '--generic-method-syntax';
|
||||
static const String resolveOnly = '--resolve-only';
|
||||
}
|
||||
|
||||
@@ -250,9 +250,17 @@ abstract class ConstantCompilerBase implements ConstantCompiler {
|
||||
ConstantValue value = getConstantValue(expression);
|
||||
if (elementType.isMalformed && !value.isNull) {
|
||||
if (isConst) {
|
||||
ErroneousElement element = elementType.element;
|
||||
reporter.reportErrorMessage(
|
||||
node, element.messageKind, element.messageArguments);
|
||||
// TODO(johnniwinther): Check that it is possible to reach this
|
||||
// point in a situation where `elementType is! MalformedType`.
|
||||
if (elementType is MalformedType) {
|
||||
ErroneousElement element = elementType.element;
|
||||
reporter.reportErrorMessage(
|
||||
node, element.messageKind, element.messageArguments);
|
||||
} else {
|
||||
assert(elementType is MethodTypeVariableType);
|
||||
reporter.reportErrorMessage(
|
||||
node, MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED);
|
||||
}
|
||||
} else {
|
||||
// We need to throw an exception at runtime.
|
||||
expression = null;
|
||||
|
||||
@@ -2734,10 +2734,18 @@ class IrBuilder {
|
||||
type = program.unaliasType(type);
|
||||
|
||||
if (type.isMalformed) {
|
||||
ErroneousElement element = type.element;
|
||||
ir.Primitive message = buildStringConstant(element.message);
|
||||
String message;
|
||||
if (type is MalformedType) {
|
||||
ErroneousElement element = type.element;
|
||||
message = element.message;
|
||||
} else {
|
||||
assert(type is MethodTypeVariableType);
|
||||
message = "Method type variables are not reified, "
|
||||
"so they cannot be tested dynamically";
|
||||
}
|
||||
ir.Primitive irMessage = buildStringConstant(message);
|
||||
return buildStaticFunctionInvocation(program.throwTypeErrorHelper,
|
||||
<ir.Primitive>[message], sourceInformation);
|
||||
<ir.Primitive>[irMessage], sourceInformation);
|
||||
}
|
||||
|
||||
List<ir.Primitive> typeArguments = const <ir.Primitive>[];
|
||||
|
||||
@@ -495,7 +495,8 @@ class TreePrinter {
|
||||
: makeFunctionBody(exp.body);
|
||||
result = new tree.FunctionExpression(
|
||||
constructorName(exp),
|
||||
// TODO(eernst): retrieve and pass the actual type variables.
|
||||
// GENERIC_METHODS: In order to support generic methods fully,
|
||||
// we must retrieve and pass the actual type variables here.
|
||||
null, // typeVariables
|
||||
parameters,
|
||||
body,
|
||||
@@ -516,7 +517,8 @@ class TreePrinter {
|
||||
tree.Node body = makeFunctionBody(exp.body);
|
||||
result = new tree.FunctionExpression(
|
||||
functionName(exp),
|
||||
// TODO(eernst): retrieve and pass the actual type variables.
|
||||
// GENERIC_METHODS: In order to support generic methods fully,
|
||||
// we must retrieve and pass the actual type variables here.
|
||||
null, // typeVariables
|
||||
parameters,
|
||||
body,
|
||||
@@ -802,7 +804,8 @@ class TreePrinter {
|
||||
} else if (stmt is FunctionDeclaration) {
|
||||
tree.FunctionExpression function = new tree.FunctionExpression(
|
||||
stmt.name != null ? makeIdentifier(stmt.name) : null,
|
||||
// TODO(eernst): retrieve and pass the actual type variables.
|
||||
// GENERIC_METHODS: In order to support generic methods fully,
|
||||
// we must retrieve and pass the actual type variables here.
|
||||
null, // typeVariables
|
||||
makeParameters(stmt.parameters),
|
||||
makeFunctionBody(stmt.body),
|
||||
@@ -971,7 +974,8 @@ class TreePrinter {
|
||||
if (param.isFunction) {
|
||||
tree.Node definition = new tree.FunctionExpression(
|
||||
makeIdentifier(param.name),
|
||||
// TODO(eernst): retrieve and pass the actual type variables.
|
||||
// GENERIC_METHODS: In order to support generic methods fully,
|
||||
// we must retrieve and pass the actual type variables here.
|
||||
null, // typeVariables
|
||||
makeParameters(param.parameters),
|
||||
null, // body
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'common/resolution.dart' show Resolution;
|
||||
import 'common.dart';
|
||||
import 'core_types.dart';
|
||||
import 'elements/elements.dart';
|
||||
import 'elements/modelx.dart' show TypeDeclarationElementX;
|
||||
import 'elements/modelx.dart' show TypeDeclarationElementX, ErroneousElementX;
|
||||
import 'ordered_typeset.dart' show OrderedTypeSet;
|
||||
import 'util/util.dart' show equalElements;
|
||||
|
||||
@@ -124,7 +124,7 @@ abstract class DartType {
|
||||
bool get isTypeVariable => kind == TypeKind.TYPE_VARIABLE;
|
||||
|
||||
/// Is [: true :] if this type is a malformed type.
|
||||
bool get isMalformed => kind == TypeKind.MALFORMED_TYPE;
|
||||
bool get isMalformed => false;
|
||||
|
||||
/// Is `true` if this type is declared by an enum.
|
||||
bool get isEnumType => false;
|
||||
@@ -164,6 +164,15 @@ abstract class DartType {
|
||||
type.accept(visitor, argument);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [DartType] which corresponds to [this] except that each
|
||||
/// contained [MethodTypeVariableType] is replaced by a [DynamicType].
|
||||
/// GENERIC_METHODS: Temporary, only used with '--generic-method-syntax'.
|
||||
DartType get dynamifyMethodTypeVariableType => this;
|
||||
|
||||
/// Returns true iff [this] is or contains a [MethodTypeVariableType].
|
||||
/// GENERIC_METHODS: Temporary, only used with '--generic-method-syntax'
|
||||
bool get containsMethodTypeVariableType => false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,6 +243,25 @@ class TypeVariableType extends DartType {
|
||||
String toString() => name;
|
||||
}
|
||||
|
||||
/// Provides a thin model of method type variables: They are treated as if
|
||||
/// their value were `dynamic` when used in a type annotation, and as a
|
||||
/// malformed type when used in an `as` or `is` expression.
|
||||
class MethodTypeVariableType extends TypeVariableType {
|
||||
MethodTypeVariableType(TypeVariableElement element) : super(element);
|
||||
|
||||
@override
|
||||
bool get treatAsDynamic => true;
|
||||
|
||||
@override
|
||||
bool get isMalformed => true;
|
||||
|
||||
@override
|
||||
DartType get dynamifyMethodTypeVariableType => const DynamicType();
|
||||
|
||||
@override
|
||||
get containsMethodTypeVariableType => true;
|
||||
}
|
||||
|
||||
/// Internal type representing the result of analyzing a statement.
|
||||
class StatementType extends DartType {
|
||||
Element get element => null;
|
||||
@@ -313,6 +341,9 @@ class MalformedType extends DartType {
|
||||
// Malformed types are treated as dynamic.
|
||||
bool get treatAsDynamic => true;
|
||||
|
||||
@override
|
||||
bool get isMalformed => true;
|
||||
|
||||
accept(DartTypeVisitor visitor, var argument) {
|
||||
return visitor.visitMalformedType(this, argument);
|
||||
}
|
||||
@@ -341,9 +372,13 @@ abstract class GenericType extends DartType {
|
||||
final TypeDeclarationElement element;
|
||||
final List<DartType> typeArguments;
|
||||
|
||||
GenericType(TypeDeclarationElement element, this.typeArguments,
|
||||
GenericType(TypeDeclarationElement element, List<DartType> typeArguments,
|
||||
{bool checkTypeArgumentCount: true})
|
||||
: this.element = element {
|
||||
: this.element = element,
|
||||
this.typeArguments = typeArguments,
|
||||
this.containsMethodTypeVariableType =
|
||||
typeArguments.any(_typeContainsMethodTypeVariableType)
|
||||
{
|
||||
assert(invariant(CURRENT_ELEMENT_SPANNABLE, element != null,
|
||||
message: "Missing element for generic type."));
|
||||
assert(invariant(element, () {
|
||||
@@ -405,6 +440,17 @@ abstract class GenericType extends DartType {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
final bool containsMethodTypeVariableType;
|
||||
|
||||
@override
|
||||
DartType get dynamifyMethodTypeVariableType {
|
||||
if (!containsMethodTypeVariableType) return this;
|
||||
List<DartType> newTypeArguments = typeArguments.map(
|
||||
(DartType type) => type.dynamifyMethodTypeVariableType).toList();
|
||||
return createInstantiation(newTypeArguments);
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
int hash = element.hashCode;
|
||||
for (DartType argument in typeArguments) {
|
||||
@@ -586,11 +632,21 @@ class FunctionType extends DartType {
|
||||
}
|
||||
|
||||
FunctionType.internal(FunctionTypedElement this.element,
|
||||
[DartType this.returnType = const DynamicType(),
|
||||
this.parameterTypes = const <DartType>[],
|
||||
this.optionalParameterTypes = const <DartType>[],
|
||||
this.namedParameters = const <String>[],
|
||||
this.namedParameterTypes = const <DartType>[]]) {
|
||||
[DartType returnType = const DynamicType(),
|
||||
List<DartType> parameterTypes = const <DartType>[],
|
||||
List<DartType> optionalParameterTypes = const <DartType>[],
|
||||
List<String> namedParameters = const <String>[],
|
||||
List<DartType> namedParameterTypes = const <DartType>[]])
|
||||
: this.returnType = returnType,
|
||||
this.parameterTypes = parameterTypes,
|
||||
this.optionalParameterTypes = optionalParameterTypes,
|
||||
this.namedParameters = namedParameters,
|
||||
this.namedParameterTypes = namedParameterTypes,
|
||||
this.containsMethodTypeVariableType =
|
||||
returnType.containsMethodTypeVariableType ||
|
||||
parameterTypes.any(_typeContainsMethodTypeVariableType) ||
|
||||
optionalParameterTypes.any(_typeContainsMethodTypeVariableType) ||
|
||||
namedParameterTypes.any(_typeContainsMethodTypeVariableType) {
|
||||
assert(invariant(
|
||||
CURRENT_ELEMENT_SPANNABLE, element == null || element.isDeclaration));
|
||||
// Assert that optional and named parameters are not used at the same time.
|
||||
@@ -718,6 +774,28 @@ class FunctionType extends DartType {
|
||||
|
||||
int computeArity() => parameterTypes.length;
|
||||
|
||||
@override
|
||||
DartType get dynamifyMethodTypeVariableType {
|
||||
if (!containsMethodTypeVariableType) return this;
|
||||
DartType eraseIt(DartType type) => type.dynamifyMethodTypeVariableType;
|
||||
DartType newReturnType = returnType.dynamifyMethodTypeVariableType;
|
||||
List<DartType> newParameterTypes = parameterTypes.map(eraseIt).toList();
|
||||
List<DartType> newOptionalParameterTypes =
|
||||
optionalParameterTypes.map(eraseIt).toList();
|
||||
List<DartType> newNamedParameterTypes =
|
||||
namedParameterTypes.map(eraseIt).toList();
|
||||
return new FunctionType.internal(
|
||||
element,
|
||||
newReturnType,
|
||||
newParameterTypes,
|
||||
newOptionalParameterTypes,
|
||||
namedParameters,
|
||||
newNamedParameterTypes);
|
||||
}
|
||||
|
||||
@override
|
||||
final bool containsMethodTypeVariableType;
|
||||
|
||||
int get hashCode {
|
||||
int hash = 3 * returnType.hashCode;
|
||||
for (DartType parameter in parameterTypes) {
|
||||
@@ -745,6 +823,9 @@ class FunctionType extends DartType {
|
||||
}
|
||||
}
|
||||
|
||||
bool _typeContainsMethodTypeVariableType(DartType type) =>
|
||||
type.containsMethodTypeVariableType;
|
||||
|
||||
class TypedefType extends GenericType {
|
||||
DartType _unaliased;
|
||||
|
||||
@@ -1347,6 +1428,15 @@ class Types implements DartTypes {
|
||||
static ClassElement getClassContext(DartType type) {
|
||||
TypeVariableType typeVariable = type.typeVariableOccurrence;
|
||||
if (typeVariable == null) return null;
|
||||
// GENERIC_METHODS: When generic method support is complete enough to
|
||||
// include a runtime value for method type variables this must be updated.
|
||||
// For full support the global assumption that all type variables are
|
||||
// declared by the same enclosing class will not hold: Both an enclosing
|
||||
// method and an enclosing class may define type variables, so the return
|
||||
// type cannot be [ClassElement] and the caller must be prepared to look in
|
||||
// two locations, not one. Currently we ignore method type variables by
|
||||
// returning in the next statement.
|
||||
if (typeVariable.element.typeDeclaration is! ClassElement) return null;
|
||||
return typeVariable.element.typeDeclaration;
|
||||
}
|
||||
|
||||
|
||||
@@ -430,6 +430,7 @@ enum MessageKind {
|
||||
TYPE_ARGUMENT_COUNT_MISMATCH,
|
||||
TYPE_VARIABLE_IN_CONSTANT,
|
||||
TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
|
||||
TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED,
|
||||
TYPEDEF_FORMAL_WITH_DEFAULT,
|
||||
UNARY_OPERATOR_BAD_ARITY,
|
||||
UNBOUND_LABEL,
|
||||
@@ -1152,6 +1153,38 @@ void main() => new C().m(null);
|
||||
"""
|
||||
]),
|
||||
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED: const MessageTemplate(
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED,
|
||||
"Method type variables are not reified.",
|
||||
howToFix: "Try using the intended upper bound of the "
|
||||
"type variable, or dynamic."
|
||||
// TODO(eernst): These examples should be commented in with an `options:`
|
||||
// specifying "--generic-method-syntax" and made to work; moreover, the
|
||||
// compiler/dart2js test 'generic_method_type_usage' should be transformed to
|
||||
// similar examples of the relevant `MessageKind` entries.
|
||||
//
|
||||
// examples: const [
|
||||
// """
|
||||
// // Method type variables are not reified, so they cannot be returned.
|
||||
// Type f<T>() => T;
|
||||
//
|
||||
// main() => f<int>();
|
||||
// """,
|
||||
// """
|
||||
// // Method type variables are not reified, so they cannot be tested dynamically.
|
||||
// bool f<T>(Object o) => o is T;
|
||||
//
|
||||
// main() => f<int>(42);
|
||||
// """,
|
||||
// """
|
||||
// // Method type variables are not reified, so they cannot be tested dynamically.
|
||||
// bool f<T>(Object o) => o as T;
|
||||
//
|
||||
// main() => f<int>(42);
|
||||
// """
|
||||
// ]
|
||||
),
|
||||
|
||||
MessageKind.INVALID_TYPE_VARIABLE_BOUND: const MessageTemplate(
|
||||
MessageKind.INVALID_TYPE_VARIABLE_BOUND,
|
||||
"'#{typeArgument}' is not a subtype of bound '#{bound}' for "
|
||||
|
||||
@@ -2703,7 +2703,12 @@ class JavaScriptImpactTransformer extends ImpactTransformer {
|
||||
if (type.isTypedef) {
|
||||
backend.compiler.world.allTypedefs.add(type.element);
|
||||
}
|
||||
if (type.isTypeVariable) {
|
||||
if (type.isTypeVariable && type is! MethodTypeVariableType) {
|
||||
// GENERIC_METHODS: The `is!` test above filters away method type
|
||||
// variables, because they have the value `dynamic` with the
|
||||
// incomplete support for generic methods offered with
|
||||
// '--generic-method-syntax'. This must be revised in order to
|
||||
// support generic methods fully.
|
||||
ClassElement cls = type.element.enclosingClass;
|
||||
backend.rti.registerClassUsingTypeVariableExpression(cls);
|
||||
registerBackendImpact(transformed, impacts.typeVariableExpression);
|
||||
|
||||
@@ -252,7 +252,12 @@ class _RuntimeTypes implements RuntimeTypes {
|
||||
compiler.resolverWorld.isChecks.forEach((DartType type) {
|
||||
if (type.isTypeVariable) {
|
||||
TypeVariableElement variable = type.element;
|
||||
classesUsingTypeVariableTests.add(variable.typeDeclaration);
|
||||
// GENERIC_METHODS: When generic method support is complete enough to
|
||||
// include a runtime value for method type variables, this may need to
|
||||
// be updated: It simply ignores method type arguments.
|
||||
if (variable.typeDeclaration is ClassElement) {
|
||||
classesUsingTypeVariableTests.add(variable.typeDeclaration);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Add is-checks that result from classes using type variables in checks.
|
||||
|
||||
@@ -719,7 +719,17 @@ class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> {
|
||||
ConstructorResult constructorResultForType(Node node, DartType type,
|
||||
{PrefixElement prefix}) {
|
||||
String name = type.name;
|
||||
if (type.isMalformed) {
|
||||
if (type.isTypeVariable) {
|
||||
return reportAndCreateErroneousConstructorElement(
|
||||
node,
|
||||
ConstructorResultKind.INVALID_TYPE,
|
||||
type,
|
||||
resolver.enclosingElement,
|
||||
name,
|
||||
MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
|
||||
{'typeVariableName': name});
|
||||
} else if (type.isMalformed) {
|
||||
// `type is MalformedType`: `MethodTypeVariableType` is handled above.
|
||||
return new ConstructorResult.forError(
|
||||
ConstructorResultKind.INVALID_TYPE, type.element, type);
|
||||
} else if (type.isInterfaceType) {
|
||||
@@ -733,15 +743,6 @@ class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> {
|
||||
name,
|
||||
MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
|
||||
{'typedefName': name});
|
||||
} else if (type.isTypeVariable) {
|
||||
return reportAndCreateErroneousConstructorElement(
|
||||
node,
|
||||
ConstructorResultKind.INVALID_TYPE,
|
||||
type,
|
||||
resolver.enclosingElement,
|
||||
name,
|
||||
MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
|
||||
{'typeVariableName': name});
|
||||
}
|
||||
return reporter.internalError(node, "Unexpected constructor type $type");
|
||||
}
|
||||
|
||||
@@ -314,10 +314,12 @@ class SignatureResolver extends MappingVisitor<FormalElementX> {
|
||||
nodes = nodes.tail;
|
||||
TypeVariableElementX variableElement =
|
||||
new TypeVariableElementX(variableName, element, index, node);
|
||||
// TODO(eernst): When type variables are implemented fully we will need
|
||||
// to resolve the actual bounds; currently we just claim [dynamic].
|
||||
// GENERIC_METHODS: When method type variables are implemented fully we
|
||||
// must resolve the actual bounds; currently we just claim that
|
||||
// every method type variable has upper bound [dynamic].
|
||||
variableElement.boundCache = const DynamicType();
|
||||
TypeVariableType variableType = new TypeVariableType(variableElement);
|
||||
TypeVariableType variableType =
|
||||
new MethodTypeVariableType(variableElement);
|
||||
variableElement.typeCache = variableType;
|
||||
return variableType;
|
||||
}, growable: false);
|
||||
|
||||
@@ -206,10 +206,6 @@ class TypeResolver {
|
||||
}
|
||||
}
|
||||
} else if (element.isTypeVariable) {
|
||||
// FIXME: check enclosing, which may be not class, not typedef (so
|
||||
// it's a generic method) then set the type to `const DynamicType()`.
|
||||
// This should later be fixed such that we don't tell the user that they
|
||||
// wrote `dynamic` anywhere.
|
||||
TypeVariableElement typeVariable = element;
|
||||
Element outer =
|
||||
visitor.enclosingElement.outermostEnclosingMemberOrTopLevel;
|
||||
|
||||
@@ -2578,13 +2578,17 @@ class SsaBuilder extends ast.Visitor
|
||||
"${localsHandler.contextClass}.");
|
||||
}
|
||||
|
||||
/// Build a [HTypeConversion] for convertion [original] to type [type].
|
||||
/// Build a [HTypeConversion] for converting [original] to type [type].
|
||||
///
|
||||
/// Invariant: [type] must be valid in the context.
|
||||
/// See [LocalsHandler.substInContext].
|
||||
HInstruction buildTypeConversion(
|
||||
HInstruction original, DartType type, int kind) {
|
||||
if (type == null) return original;
|
||||
// GENERIC_METHODS: The following statement was added for parsing and
|
||||
// ignoring method type variables; must be generalized for full support of
|
||||
// generic methods.
|
||||
type = type.dynamifyMethodTypeVariableType;
|
||||
type = type.unaliased;
|
||||
assert(assertTypeInContext(type, original));
|
||||
if (type.isInterfaceType && !type.treatAsRaw) {
|
||||
@@ -3805,8 +3809,15 @@ class SsaBuilder extends ast.Visitor
|
||||
void visitAs(ast.Send node, ast.Node expression, DartType type, _) {
|
||||
HInstruction expressionInstruction = visitAndPop(expression);
|
||||
if (type.isMalformed) {
|
||||
ErroneousElement element = type.element;
|
||||
generateTypeError(node, element.message);
|
||||
String message;
|
||||
if (type is MalformedType) {
|
||||
ErroneousElement element = type.element;
|
||||
message = element.message;
|
||||
} else {
|
||||
assert(type is MethodTypeVariableType);
|
||||
message = "Method type variables are not reified.";
|
||||
}
|
||||
generateTypeError(node, message);
|
||||
} else {
|
||||
HInstruction converted = buildTypeConversion(expressionInstruction,
|
||||
localsHandler.substInContext(type), HTypeConversion.CAST_TYPE_CHECK);
|
||||
@@ -3832,7 +3843,20 @@ class SsaBuilder extends ast.Visitor
|
||||
HInstruction buildIsNode(
|
||||
ast.Node node, DartType type, HInstruction expression) {
|
||||
type = localsHandler.substInContext(type).unaliased;
|
||||
if (type.isFunctionType) {
|
||||
if (type.isMalformed) {
|
||||
String message;
|
||||
if (type is MethodTypeVariableType) {
|
||||
message = "Method type variables are not reified, "
|
||||
"so they cannot be tested with an `is` expression.";
|
||||
} else {
|
||||
assert(type is MalformedType);
|
||||
ErroneousElement element = type.element;
|
||||
message = element.message;
|
||||
}
|
||||
generateTypeError(node, message);
|
||||
HInstruction call = pop();
|
||||
return new HIs.compound(type, expression, call, backend.boolType);
|
||||
} else if (type.isFunctionType) {
|
||||
List arguments = [buildFunctionType(type), expression];
|
||||
pushInvokeDynamic(
|
||||
node,
|
||||
@@ -3867,11 +3891,6 @@ class SsaBuilder extends ast.Visitor
|
||||
pushInvokeStatic(node, helper, inputs, typeMask: backend.boolType);
|
||||
HInstruction call = pop();
|
||||
return new HIs.compound(type, expression, call, backend.boolType);
|
||||
} else if (type.isMalformed) {
|
||||
ErroneousElement element = type.element;
|
||||
generateTypeError(node, element.message);
|
||||
HInstruction call = pop();
|
||||
return new HIs.compound(type, expression, call, backend.boolType);
|
||||
} else {
|
||||
if (backend.hasDirectCheckFor(type)) {
|
||||
return new HIs.direct(type, expression, backend.boolType);
|
||||
@@ -5337,12 +5356,19 @@ class SsaBuilder extends ast.Visitor
|
||||
/// Generate the literal for [typeVariable] in the current context.
|
||||
void generateTypeVariableLiteral(
|
||||
ast.Send node, TypeVariableType typeVariable) {
|
||||
DartType type = localsHandler.substInContext(typeVariable);
|
||||
HInstruction value = analyzeTypeArgument(type,
|
||||
sourceInformation: sourceInformationBuilder.buildGet(node));
|
||||
pushInvokeStatic(node, helpers.runtimeTypeToString, [value],
|
||||
typeMask: backend.stringType);
|
||||
pushInvokeStatic(node, helpers.createRuntimeType, [pop()]);
|
||||
// GENERIC_METHODS: This provides thin support for method type variables
|
||||
// by treating them as malformed when evaluated as a literal. For full
|
||||
// support of generic methods this must be revised.
|
||||
if (typeVariable is MethodTypeVariableType) {
|
||||
generateTypeError(node, "Method type variables are not reified");
|
||||
} else {
|
||||
DartType type = localsHandler.substInContext(typeVariable);
|
||||
HInstruction value = analyzeTypeArgument(type,
|
||||
sourceInformation: sourceInformationBuilder.buildGet(node));
|
||||
pushInvokeStatic(node, helpers.runtimeTypeToString, [value],
|
||||
typeMask: backend.stringType);
|
||||
pushInvokeStatic(node, helpers.createRuntimeType, [pop()]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a call to a type literal.
|
||||
|
||||
@@ -780,6 +780,8 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
||||
return inputType.isInMask(checkedType, classWorld) ? input : node;
|
||||
}
|
||||
|
||||
HInstruction removeCheck(HCheck node) => node.checkedInput;
|
||||
|
||||
VariableElement findConcreteFieldForDynamicAccess(
|
||||
HInstruction receiver, Selector selector) {
|
||||
TypeMask receiverType = receiver.instructionType;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/// Dart test verifying that the parser can handle type parameterization of
|
||||
/// local function declarations, and declarations of function parameters.
|
||||
|
||||
library generic_functions_test;
|
||||
library generic_local_functions_test;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2016, 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.
|
||||
//
|
||||
// DartOptions=--generic-method-syntax
|
||||
|
||||
/// Dart test on the usage of method type arguments in a function typed
|
||||
/// parameter declaration.
|
||||
|
||||
library generic_methods_function_type_test;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
class C<V> {
|
||||
U m1<U>(U f(V v), V v) => f(v);
|
||||
V m2<U>(V f(U v), U u) => f(u);
|
||||
}
|
||||
|
||||
main() {
|
||||
Expect.equals(new C<int>().m1<int>((x) => x, 10), 10);
|
||||
Expect.equals(new C<int>().m2<int>((x) => x, 20), 20);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
analyzer:
|
||||
language:
|
||||
enableGenericMethods: true
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2016, 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.
|
||||
//
|
||||
// DartOptions=--generic-method-syntax
|
||||
|
||||
/// Dart test on the usage of method type arguments in object creation. With
|
||||
/// '--generic-method-syntax', the type argument is available at runtime,
|
||||
/// but erased to `dynamic`.
|
||||
|
||||
library generic_methods_new_test;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
class C<E> {
|
||||
E e;
|
||||
C(this.e);
|
||||
}
|
||||
|
||||
C<T> f1<T>(T t) => new C<T>(t);
|
||||
|
||||
List<T> f2<T>(T t) => <T>[t];
|
||||
|
||||
main() {
|
||||
C c = f1<int>(42);
|
||||
List i = f2<String>("Hello!");
|
||||
Expect.isTrue(c is C<int> && c is C<String>); // C<dynamic>.
|
||||
Expect.isTrue(i is List<String> && i is List<int>); // List<dynamic>.
|
||||
Expect.equals(c.e, 42);
|
||||
Expect.equals(i[0], "Hello!");
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
analyzer:
|
||||
language:
|
||||
enableGenericMethods: true
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2016, 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.
|
||||
//
|
||||
// DartOptions=--generic-method-syntax
|
||||
|
||||
/// Dart test on the usage of method type arguments in type expressions. With
|
||||
/// '--generic-method-syntax', the type argument is available at runtime,
|
||||
/// but erased to `dynamic`.
|
||||
|
||||
library generic_methods_type_expression_test;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
bool f1<T>(Object o) => o is T;
|
||||
|
||||
bool f2<T>(Object o) => o is List<T>;
|
||||
|
||||
bool f3<T>(Object o) => o is! T;
|
||||
|
||||
bool f4<T>(Object o) => o is! List<T>;
|
||||
|
||||
T f5<T>(Object o) => o as T;
|
||||
|
||||
List<T> f6<T>(Object o) => o as List<T>;
|
||||
|
||||
Type f7<T>() => T;
|
||||
|
||||
class TypeValue<X> {
|
||||
Type get value => X;
|
||||
}
|
||||
|
||||
Type f8<T>() => new TypeValue<List<T>>().value;
|
||||
|
||||
main() {
|
||||
String s = "Hello!";
|
||||
List<String> ss = <String>[s];
|
||||
Expect.throws(() => f1<int>(42), (e) => e is TypeError);
|
||||
Expect.throws(() => f1<String>(42), (e) => e is TypeError);
|
||||
Expect.equals(f2<int>(<int>[42]), true);
|
||||
Expect.equals(f2<String>(<int>[42]), true); // `is List<dynamic>` is true.
|
||||
Expect.throws(() => f3<int>(42), (e) => e is TypeError);
|
||||
Expect.throws(() => f3<String>(42), (e) => e is TypeError);
|
||||
Expect.equals(f4<int>(<int>[42]), false);
|
||||
Expect.equals(f4<String>(<int>[42]), false); // `is! List<dynamic>` is false.
|
||||
Expect.throws(() => f5<String>(s), (e) => e is TypeError);
|
||||
Expect.throws(() => f5<int>(s), (e) => e is TypeError);
|
||||
Expect.equals(f6<String>(ss), ss);
|
||||
Expect.equals(f6<int>(ss), ss); // `as List<dynamic>` succeeds.
|
||||
Expect.throws(() => f7<int>(), (e) => e is TypeError);
|
||||
Expect.equals(f8<int>(), List); // Returns `List<dynamic>`.
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
analyzer:
|
||||
language:
|
||||
enableGenericMethods: true
|
||||
@@ -49,6 +49,9 @@ generic_methods_test: CompiletimeError # Issue 25869
|
||||
generic_functions_test: CompiletimeError # Issue 25869
|
||||
generic_local_functions_test: CompiletimeError # Issue 25869
|
||||
generic_sends_test: CompiletimeError # Issue 25869
|
||||
generic_methods_new_test: CompiletimeError # Issue 25869
|
||||
generic_methods_function_type_test: CompiletimeError # Issue 25869
|
||||
generic_methods_type_expression_test: CompiletimeError # Issue 25869
|
||||
|
||||
[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
|
||||
|
||||
@@ -94,6 +97,9 @@ generic_methods_test: RuntimeError # Issue 25869
|
||||
generic_functions_test: RuntimeError # Issue 25869
|
||||
generic_local_functions_test: RuntimeError # Issue 25869
|
||||
generic_sends_test: RuntimeError # Issue 25869
|
||||
generic_methods_new_test: RuntimeError # Issue 25869
|
||||
generic_methods_function_type_test: RuntimeError # Issue 25869
|
||||
generic_methods_type_expression_test: RuntimeError # Issue 25869
|
||||
config_import_test: Skip # Issue 26250
|
||||
|
||||
[ $compiler == none && $runtime == dartium && $system == linux && $arch != x64 ]
|
||||
|
||||
@@ -506,3 +506,6 @@ generic_functions_test: CompileTimeError # Issue 25868
|
||||
generic_local_functions_test: CompileTimeError # Issue 25868
|
||||
generic_methods_test: CompileTimeError # Issue 25868
|
||||
generic_sends_test: CompileTimeError # Issue 25868
|
||||
generic_methods_new_test: CompiletimeError # Issue 25868
|
||||
generic_methods_function_type_test: CompiletimeError # Issue 25868
|
||||
generic_methods_type_expression_test: CompiletimeError # Issue 25868
|
||||
|
||||
@@ -50,6 +50,9 @@ generic_functions_test: CompileTimeError # DartOptions not passed to compiler.
|
||||
generic_local_functions_test: CompileTimeError # DartOptions not passed to compiler.
|
||||
generic_methods_test: CompileTimeError # DartOptions not passed to compiler.
|
||||
generic_sends_test: CompileTimeError # DartOptions not passed to compiler.
|
||||
generic_methods_new_test: CompiletimeError # DartOptions not passed to compiler.
|
||||
generic_methods_function_type_test: CompiletimeError # DartOptions not passed to compiler.
|
||||
generic_methods_type_expression_test: CompiletimeError # DartOptions not passed to compiler.
|
||||
|
||||
[ $compiler == dart2js ]
|
||||
invocation_mirror_empty_arguments_test: Fail # Issue 24331
|
||||
@@ -132,9 +135,6 @@ malbounded_type_test_test/03: Fail # Issue 14121
|
||||
malbounded_type_test_test/04: Fail # Issue 14121
|
||||
malbounded_type_test2_test: Fail # Issue 14121
|
||||
default_factory2_test/01: Fail # Issue 14121
|
||||
generic_functions_test: Crash # Issue 26436
|
||||
generic_local_functions_test: Crash # Issue 26436
|
||||
generic_methods_test: Crash # Issue 26436
|
||||
|
||||
[ $compiler == dart2js && $unchecked ]
|
||||
type_checks_in_factory_method_test: RuntimeError # Issue 12746
|
||||
|
||||
Reference in New Issue
Block a user