diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart index fba840121bc..013e997541e 100644 --- a/pkg/compiler/lib/src/commandline_options.dart +++ b/pkg/compiler/lib/src/commandline_options.dart @@ -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'; } diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart index 0eae100e169..ed39469b414 100644 --- a/pkg/compiler/lib/src/compile_time_constants.dart +++ b/pkg/compiler/lib/src/compile_time_constants.dart @@ -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; diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart index dd756c69567..3e1f9bf0d1e 100644 --- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart +++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart @@ -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, - [message], sourceInformation); + [irMessage], sourceInformation); } List typeArguments = const []; diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart index 03f0ba1f973..469858d0d96 100644 --- a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart +++ b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart @@ -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 diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart index 685077d0b63..ba7fa5655d4 100644 --- a/pkg/compiler/lib/src/dart_types.dart +++ b/pkg/compiler/lib/src/dart_types.dart @@ -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 typeArguments; - GenericType(TypeDeclarationElement element, this.typeArguments, + GenericType(TypeDeclarationElement element, List 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 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 [], - this.optionalParameterTypes = const [], - this.namedParameters = const [], - this.namedParameterTypes = const []]) { + [DartType returnType = const DynamicType(), + List parameterTypes = const [], + List optionalParameterTypes = const [], + List namedParameters = const [], + List namedParameterTypes = const []]) + : 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 newParameterTypes = parameterTypes.map(eraseIt).toList(); + List newOptionalParameterTypes = + optionalParameterTypes.map(eraseIt).toList(); + List 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; } diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart index bbe777e09c6..830a010ad39 100644 --- a/pkg/compiler/lib/src/diagnostics/messages.dart +++ b/pkg/compiler/lib/src/diagnostics/messages.dart @@ -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; +// +// main() => f(); +// """, +// """ +// // Method type variables are not reified, so they cannot be tested dynamically. +// bool f(Object o) => o is T; +// +// main() => f(42); +// """, +// """ +// // Method type variables are not reified, so they cannot be tested dynamically. +// bool f(Object o) => o as T; +// +// main() => f(42); +// """ +// ] + ), + MessageKind.INVALID_TYPE_VARIABLE_BOUND: const MessageTemplate( MessageKind.INVALID_TYPE_VARIABLE_BOUND, "'#{typeArgument}' is not a subtype of bound '#{bound}' for " diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart index 5f334e39e43..e8f43caacde 100644 --- a/pkg/compiler/lib/src/js_backend/backend.dart +++ b/pkg/compiler/lib/src/js_backend/backend.dart @@ -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); diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart index 036e52ae628..369cec030ff 100644 --- a/pkg/compiler/lib/src/js_backend/runtime_types.dart +++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart @@ -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. diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart index 17bd6e030d2..7a4dbc68af7 100644 --- a/pkg/compiler/lib/src/resolution/constructors.dart +++ b/pkg/compiler/lib/src/resolution/constructors.dart @@ -719,7 +719,17 @@ class ConstructorResolver extends CommonResolverVisitor { 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 { 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"); } diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart index 33a8f2f336b..d3f3264e06a 100644 --- a/pkg/compiler/lib/src/resolution/signatures.dart +++ b/pkg/compiler/lib/src/resolution/signatures.dart @@ -314,10 +314,12 @@ class SignatureResolver extends MappingVisitor { 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); diff --git a/pkg/compiler/lib/src/resolution/type_resolver.dart b/pkg/compiler/lib/src/resolution/type_resolver.dart index e1a076df698..9837a099948 100644 --- a/pkg/compiler/lib/src/resolution/type_resolver.dart +++ b/pkg/compiler/lib/src/resolution/type_resolver.dart @@ -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; diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart index f8c3ad057a7..5b13bbcf88a 100644 --- a/pkg/compiler/lib/src/ssa/builder.dart +++ b/pkg/compiler/lib/src/ssa/builder.dart @@ -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. diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart index a4ee03951d5..c7fb15d3005 100644 --- a/pkg/compiler/lib/src/ssa/optimize.dart +++ b/pkg/compiler/lib/src/ssa/optimize.dart @@ -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; diff --git a/tests/language/generic_local_functions_test.dart b/tests/language/generic_local_functions_test.dart index 21bd7a755a8..1ec1227085e 100644 --- a/tests/language/generic_local_functions_test.dart +++ b/tests/language/generic_local_functions_test.dart @@ -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"; diff --git a/tests/language/generic_methods_function_type_test.dart b/tests/language/generic_methods_function_type_test.dart new file mode 100644 index 00000000000..17a4c1a366c --- /dev/null +++ b/tests/language/generic_methods_function_type_test.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 { + U m1(U f(V v), V v) => f(v); + V m2(V f(U v), U u) => f(u); +} + +main() { + Expect.equals(new C().m1((x) => x, 10), 10); + Expect.equals(new C().m2((x) => x, 20), 20); +} + diff --git a/tests/language/generic_methods_function_type_test.options b/tests/language/generic_methods_function_type_test.options new file mode 100644 index 00000000000..86e2aac8874 --- /dev/null +++ b/tests/language/generic_methods_function_type_test.options @@ -0,0 +1,3 @@ +analyzer: + language: + enableGenericMethods: true diff --git a/tests/language/generic_methods_new_test.dart b/tests/language/generic_methods_new_test.dart new file mode 100644 index 00000000000..ea23b949d91 --- /dev/null +++ b/tests/language/generic_methods_new_test.dart @@ -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; + C(this.e); +} + +C f1(T t) => new C(t); + +List f2(T t) => [t]; + +main() { + C c = f1(42); + List i = f2("Hello!"); + Expect.isTrue(c is C && c is C); // C. + Expect.isTrue(i is List && i is List); // List. + Expect.equals(c.e, 42); + Expect.equals(i[0], "Hello!"); +} diff --git a/tests/language/generic_methods_new_test.options b/tests/language/generic_methods_new_test.options new file mode 100644 index 00000000000..86e2aac8874 --- /dev/null +++ b/tests/language/generic_methods_new_test.options @@ -0,0 +1,3 @@ +analyzer: + language: + enableGenericMethods: true diff --git a/tests/language/generic_methods_type_expression_test.dart b/tests/language/generic_methods_type_expression_test.dart new file mode 100644 index 00000000000..cbe08026c4f --- /dev/null +++ b/tests/language/generic_methods_type_expression_test.dart @@ -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(Object o) => o is T; + +bool f2(Object o) => o is List; + +bool f3(Object o) => o is! T; + +bool f4(Object o) => o is! List; + +T f5(Object o) => o as T; + +List f6(Object o) => o as List; + +Type f7() => T; + +class TypeValue { + Type get value => X; +} + +Type f8() => new TypeValue>().value; + +main() { + String s = "Hello!"; + List ss = [s]; + Expect.throws(() => f1(42), (e) => e is TypeError); + Expect.throws(() => f1(42), (e) => e is TypeError); + Expect.equals(f2([42]), true); + Expect.equals(f2([42]), true); // `is List` is true. + Expect.throws(() => f3(42), (e) => e is TypeError); + Expect.throws(() => f3(42), (e) => e is TypeError); + Expect.equals(f4([42]), false); + Expect.equals(f4([42]), false); // `is! List` is false. + Expect.throws(() => f5(s), (e) => e is TypeError); + Expect.throws(() => f5(s), (e) => e is TypeError); + Expect.equals(f6(ss), ss); + Expect.equals(f6(ss), ss); // `as List` succeeds. + Expect.throws(() => f7(), (e) => e is TypeError); + Expect.equals(f8(), List); // Returns `List`. +} diff --git a/tests/language/generic_methods_type_expression_test.options b/tests/language/generic_methods_type_expression_test.options new file mode 100644 index 00000000000..86e2aac8874 --- /dev/null +++ b/tests/language/generic_methods_type_expression_test.options @@ -0,0 +1,3 @@ +analyzer: + language: + enableGenericMethods: true diff --git a/tests/language/language.status b/tests/language/language.status index 4b75506b45e..b64df8136b1 100644 --- a/tests/language/language.status +++ b/tests/language/language.status @@ -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 ] diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status index 2035434e2e0..a0e3ee5b072 100644 --- a/tests/language/language_analyzer2.status +++ b/tests/language/language_analyzer2.status @@ -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 diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status index 25902c144b8..b61dd39a6d5 100644 --- a/tests/language/language_dart2js.status +++ b/tests/language/language_dart2js.status @@ -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