mirror of
https://github.com/dart-lang/sdk
synced 2024-09-04 16:03:44 +00:00
Reenable warnings/hints for method type variables in dart2js
Change-Id: I09662afc8b1a4e8c9fdbfe2e342e80ea58351593 Reviewed-on: https://dart-review.googlesource.com/32060 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
This commit is contained in:
parent
a4d2d87238
commit
ab636dfbd1
|
@ -268,10 +268,6 @@ abstract class ConstantCompilerBase implements ConstantCompiler {
|
|||
ErroneousElement element = elementType.element;
|
||||
reporter.reportErrorMessage(
|
||||
node, element.messageKind, element.messageArguments);
|
||||
} else {
|
||||
assert(elementType is MethodTypeVariableType);
|
||||
// Used to `reportErrorMessage` here, but with Dart 2 upcoming
|
||||
// very soon we do not emit this message any more.
|
||||
}
|
||||
} else {
|
||||
// We need to throw an exception at runtime.
|
||||
|
|
|
@ -404,6 +404,8 @@ enum MessageKind {
|
|||
TYPE_ARGUMENT_COUNT_MISMATCH,
|
||||
TYPE_VARIABLE_IN_CONSTANT,
|
||||
TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
|
||||
TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED,
|
||||
TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC,
|
||||
TYPEDEF_FORMAL_WITH_DEFAULT,
|
||||
UNARY_OPERATOR_BAD_ARITY,
|
||||
UNBOUND_LABEL,
|
||||
|
@ -1195,6 +1197,43 @@ class C<T> {
|
|||
}
|
||||
|
||||
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 do not have a runtime value.",
|
||||
howToFix: "Try using the upper bound of the type variable, "
|
||||
"or refactor the code to avoid needing this runtime value.",
|
||||
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);
|
||||
"""
|
||||
]),
|
||||
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC:
|
||||
const MessageTemplate(
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC,
|
||||
"Method type variables are treated as `dynamic` in `as` "
|
||||
"expressions.",
|
||||
howToFix:
|
||||
"Try using the upper bound of the type variable, or check "
|
||||
"that the blind success of the test does not introduce bugs.",
|
||||
examples: const [
|
||||
"""
|
||||
// Method type variables are not reified, so they cannot be tested dynamically.
|
||||
bool f<T>(Object o) => o as T;
|
||||
|
||||
main() => f<int>(42);
|
||||
"""
|
||||
]),
|
||||
|
||||
|
|
|
@ -1131,6 +1131,13 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
sendStructure = new IsStructure(type);
|
||||
}
|
||||
|
||||
// GENERIC_METHODS: Method type variables are not reified so we must warn
|
||||
// about the error which will occur at runtime.
|
||||
if (type is MethodTypeVariableType) {
|
||||
reporter.reportWarningMessage(
|
||||
node, MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED);
|
||||
}
|
||||
|
||||
registry.registerTypeUse(new TypeUse.isCheck(type));
|
||||
registry.registerSendStructure(node, sendStructure);
|
||||
return const NoneResult();
|
||||
|
@ -1145,6 +1152,13 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
ResolutionDartType type =
|
||||
resolveTypeAnnotation(typeNode, registerCheckedModeCheck: false);
|
||||
|
||||
// GENERIC_METHODS: Method type variables are not reified, so we must inform
|
||||
// the developer about the potentially bug-inducing semantics.
|
||||
if (type is MethodTypeVariableType) {
|
||||
reporter.reportHintMessage(
|
||||
node, MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC);
|
||||
}
|
||||
|
||||
registry.registerTypeUse(new TypeUse.asCast(type));
|
||||
registry.registerSendStructure(node, new AsStructure(type));
|
||||
return const NoneResult();
|
||||
|
@ -1913,6 +1927,12 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
// TODO(johnniwinther): Clean up registration of elements and selectors
|
||||
// for this case.
|
||||
} else {
|
||||
// GENERIC_METHODS: Method type variables are not reified so we must warn
|
||||
// about the error which will occur at runtime.
|
||||
if (element.type is MethodTypeVariableType) {
|
||||
reporter.reportWarningMessage(
|
||||
node, MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED);
|
||||
}
|
||||
semantics = new StaticAccess.typeParameterTypeLiteral(element);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
import 'package:async_helper/async_helper.dart';
|
||||
import 'package:compiler/src/diagnostics/messages.dart';
|
||||
import 'package:expect/expect.dart';
|
||||
import '../memory_compiler.dart';
|
||||
|
||||
runTest(String code,
|
||||
{List<MessageKind> expectedWarnings: const <MessageKind>[],
|
||||
List<MessageKind> expectedHints: const <MessageKind>[]}) async {
|
||||
print('--test--------------------------------------------------------------');
|
||||
print(code);
|
||||
DiagnosticCollector collector = new DiagnosticCollector();
|
||||
await runCompiler(
|
||||
memorySourceFiles: {'main.dart': code}, diagnosticHandler: collector);
|
||||
Expect.equals(0, collector.errors.length, "Unexpected errors.");
|
||||
Expect.listEquals(
|
||||
expectedWarnings,
|
||||
collector.warnings.map((m) => m.messageKind).toList(),
|
||||
"Unexpected warnings.");
|
||||
Expect.listEquals(expectedHints,
|
||||
collector.hints.map((m) => m.messageKind).toList(), "Unexpected hints.");
|
||||
}
|
||||
|
||||
class Test {
|
||||
final String code;
|
||||
final List<MessageKind> warnings;
|
||||
final List<MessageKind> hints;
|
||||
|
||||
const Test(this.code,
|
||||
{this.warnings: const <MessageKind>[],
|
||||
this.hints: const <MessageKind>[]});
|
||||
}
|
||||
|
||||
const List<Test> tests = const <Test>[
|
||||
/// Is-test on method type variable in unused static method.
|
||||
const Test('''
|
||||
method<T>(T t) => t is T;
|
||||
main() {}
|
||||
'''),
|
||||
|
||||
/// Is-test on method type variable in used static method.
|
||||
const Test('''
|
||||
method<T>(T t) => t is T;
|
||||
main() => method<int>(0);
|
||||
''', warnings: const <MessageKind>[
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED
|
||||
]),
|
||||
|
||||
/// Is-test on method type variable in unused instance method.
|
||||
const Test('''
|
||||
class C {
|
||||
method<T>(T t) => t is T;
|
||||
}
|
||||
main() => new C();
|
||||
'''),
|
||||
|
||||
/// Is-test on method type variable in used instance method.
|
||||
const Test('''
|
||||
class C {
|
||||
method<T>(T t) => t is T;
|
||||
}
|
||||
main() => new C().method<int>(0);
|
||||
''', warnings: const <MessageKind>[
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED
|
||||
]),
|
||||
|
||||
/// As-cast on method type variable in unused static method.
|
||||
const Test('''
|
||||
method<T>(T t) => t as T;
|
||||
main() {}
|
||||
'''),
|
||||
|
||||
/// As-cast on method type variable in used static method.
|
||||
const Test('''
|
||||
method<T>(T t) => t as T;
|
||||
main() => method<int>(0);
|
||||
''', hints: const <MessageKind>[
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC
|
||||
]),
|
||||
|
||||
/// As-cast on method type variable in unused instance method.
|
||||
const Test('''
|
||||
class C {
|
||||
method<T>(T t) => t as T;
|
||||
}
|
||||
main() => new C();
|
||||
'''),
|
||||
|
||||
/// As-cast on method type variable in used instance method.
|
||||
const Test('''
|
||||
class C {
|
||||
method<T>(T t) => t as T;
|
||||
}
|
||||
main() => new C().method<int>(0);
|
||||
''', hints: const <MessageKind>[
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC
|
||||
]),
|
||||
|
||||
/// Method type variable literal in unused static method.
|
||||
const Test('''
|
||||
method<T>() => T;
|
||||
main() {}
|
||||
'''),
|
||||
|
||||
/// Method type variable literal in used static method.
|
||||
const Test('''
|
||||
method<T>() => T;
|
||||
main() => method<int>();
|
||||
''', warnings: const <MessageKind>[
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED
|
||||
]),
|
||||
|
||||
/// Method type variable literal in unused instance method.
|
||||
const Test('''
|
||||
class C {
|
||||
method<T>() => T;
|
||||
}
|
||||
main() => new C();
|
||||
'''),
|
||||
|
||||
/// Method type variable literal in used instance method.
|
||||
const Test('''
|
||||
class C {
|
||||
method<T>() => T;
|
||||
}
|
||||
main() => new C().method<int>();
|
||||
''', warnings: const <MessageKind>[
|
||||
MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED
|
||||
]),
|
||||
];
|
||||
|
||||
main() {
|
||||
asyncTest(() async {
|
||||
for (Test test in tests) {
|
||||
await runTest(
|
||||
test.code,
|
||||
expectedWarnings: test.warnings,
|
||||
expectedHints: test.hints,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue