From 50eb282f87a7471d7eef4b81e2509a9c37439998 Mon Sep 17 00:00:00 2001 From: Vijay Menon Date: Tue, 25 Aug 2015 10:45:08 -0700 Subject: [PATCH] Infer parameter types on overrides Fixes #105 This overlaps with brian's recent CL moving override inference logic. If this looks good, we'll need to move it over as well. R=brianwilkerson@google.com, leafp@google.com Review URL: https://codereview.chromium.org/1311863005 . --- pkg/dev_compiler/lib/runtime/dart/js.js | 12 +++--- .../lib/src/checker/resolver.dart | 40 ++++++++++++++----- .../test/checker/checker_test.dart | 10 ++--- pkg/dev_compiler/tool/sdk_expected_errors.txt | 16 ++++---- 4 files changed, 49 insertions(+), 29 deletions(-) diff --git a/pkg/dev_compiler/lib/runtime/dart/js.js b/pkg/dev_compiler/lib/runtime/dart/js.js index df934172693f..fb4040e4d069 100644 --- a/pkg/dev_compiler/lib/runtime/dart/js.js +++ b/pkg/dev_compiler/lib/runtime/dart/js.js @@ -201,15 +201,15 @@ dart_library.library('dart/js', null, /* Imports */[ } } get(index) { - if (dart.is(index, core.num) && dart.equals(index, dart.dsend(index, 'toInt'))) { - this[_checkIndex](dart.as(index, core.int)); + if (dart.is(index, core.num) && index == index[dartx.toInt]()) { + this[_checkIndex](index); } return dart.as(super.get(index), E); } set(index, value) { dart.as(value, E); - if (dart.is(index, core.num) && dart.equals(index, dart.dsend(index, 'toInt'))) { - this[_checkIndex](dart.as(index, core.int)); + if (dart.is(index, core.num) && index == index[dartx.toInt]()) { + this[_checkIndex](index); } super.set(index, value); } @@ -282,8 +282,8 @@ dart_library.library('dart/js', null, /* Imports */[ methods: () => ({ [_checkIndex]: [dart.dynamic, [core.int]], [_checkInsertIndex]: [dart.dynamic, [core.int]], - get: [E, [dart.dynamic]], - set: [dart.void, [dart.dynamic, E]], + get: [E, [core.int]], + set: [dart.void, [core.int, E]], add: [dart.void, [E]], addAll: [dart.void, [core.Iterable$(E)]], insert: [dart.void, [core.int, E]], diff --git a/pkg/dev_compiler/lib/src/checker/resolver.dart b/pkg/dev_compiler/lib/src/checker/resolver.dart index b4954453288a..655540c52163 100644 --- a/pkg/dev_compiler/lib/src/checker/resolver.dart +++ b/pkg/dev_compiler/lib/src/checker/resolver.dart @@ -168,10 +168,10 @@ class LibraryResolverWithInference extends LibraryResolver { .forEach((f) => _inferFieldTypeFromOverride(f, pending)); if (pending.isNotEmpty) _inferVariableFromInitializer(pending); - // Infer return-types from overrides + // Infer return-types and param-types from overrides cls.members .where((m) => m is MethodDeclaration && !m.isStatic) - .forEach(_inferMethodReturnTypeFromOverride); + .forEach(_inferMethodTypesFromOverride); } else { _inferVariableFromInitializer(cls.members .where(_isInstanceField) @@ -231,18 +231,38 @@ class LibraryResolverWithInference extends LibraryResolver { } } - void _inferMethodReturnTypeFromOverride(MethodDeclaration method) { + void _inferMethodTypesFromOverride(MethodDeclaration method) { var methodElement = method.element; - if ((methodElement is MethodElement || - methodElement is PropertyAccessorElement) && - methodElement.returnType.isDynamic && - method.returnType == null) { - var enclosingElement = methodElement.enclosingElement as ClassElement; - var type = searchTypeFor(enclosingElement.type, methodElement); - if (type != null && !type.returnType.isDynamic) { + if (methodElement is! MethodElement && + methodElement is! PropertyAccessorElement) return; + + var enclosingElement = methodElement.enclosingElement as ClassElement; + FunctionType type = null; + + // Infer the return type if omitted + if (methodElement.returnType.isDynamic && method.returnType == null) { + type = searchTypeFor(enclosingElement.type, methodElement); + if (type == null) return; + if (!type.returnType.isDynamic) { methodElement.returnType = type.returnType; } } + + // Infer parameter types if omitted + if (method.parameters == null) return; + var parameters = method.parameters.parameters; + var length = parameters.length; + for (int i = 0; i < length; ++i) { + var parameter = parameters[i]; + if (parameter is DefaultFormalParameter) parameter = parameter.parameter; + if (parameter is SimpleFormalParameter && parameter.type == null) { + type = type ?? searchTypeFor(enclosingElement.type, methodElement); + if (type == null) return; + if (type.parameters.length > i && !type.parameters[i].type.isDynamic) { + parameter.element.type = type.parameters[i].type; + } + } + } } void _inferVariableFromInitializer(Iterable variables) { diff --git a/pkg/dev_compiler/test/checker/checker_test.dart b/pkg/dev_compiler/test/checker/checker_test.dart index 1a1abc134469..82173c4fe50c 100644 --- a/pkg/dev_compiler/test/checker/checker_test.dart +++ b/pkg/dev_compiler/test/checker/checker_test.dart @@ -1488,7 +1488,7 @@ void main() { class Child extends Base { void set f1(A value) {} /*severe:InvalidMethodOverride*/void set f2(C value) {} - /*severe:InvalidMethodOverride*/void set f3(value) {} + void set f3(value) {} /*severe:InvalidMethodOverride*/void set f4(dynamic value) {} set f5(B value) {} } @@ -1518,7 +1518,7 @@ void main() { void set f1(A value) {} /*severe:InvalidMethodOverride*/void set f2(C value) {} - /*severe:InvalidMethodOverride*/void set f3(value) {} + void set f3(value) {} /*severe:InvalidMethodOverride*/void set f4(dynamic value) {} set f5(B value) {} } @@ -1547,7 +1547,7 @@ void main() { /*severe:InvalidMethodOverride*/C m2(C value) {} /*severe:InvalidMethodOverride*/A m3(C value) {} C m4(A value) {} - /*severe:InvalidMethodOverride*/m5(value) {} + m5(value) {} /*severe:InvalidMethodOverride*/dynamic m6(dynamic value) {} } ''' @@ -2025,14 +2025,14 @@ void main() { implements I1 {} class T2 extends Base implements I1 { - /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {} + /*severe:InvalidMethodOverride*/m(a) {} } class T3 extends Object with /*severe:InvalidMethodOverride*/Base implements I1 {} class T4 extends Object with Base implements I1 { - /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {} + /*severe:InvalidMethodOverride*/m(a) {} } ''' }); diff --git a/pkg/dev_compiler/tool/sdk_expected_errors.txt b/pkg/dev_compiler/tool/sdk_expected_errors.txt index 69becd926f65..26168c3220ef 100644 --- a/pkg/dev_compiler/tool/sdk_expected_errors.txt +++ b/pkg/dev_compiler/tool/sdk_expected_errors.txt @@ -3,23 +3,23 @@ severe: [AnalyzerMessage] Classes cannot implement 'num' (dart:_interceptors/js_ severe: [AnalyzerMessage] The return type 'JSNumber' is not a 'double', as defined by the method 'toDouble' (dart:_interceptors/js_number.dart, line 110, col 17) severe: [StaticTypeError] Type check failed: this (JSNumber) is not of type double (dart:_interceptors/js_number.dart, line 110, col 17) severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.sign (() → num) is not a subtype of int.sign (() → int). (dart:_interceptors/js_number.dart, line 349, col 13) -severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.>> ((num) → num) is not a subtype of int.>> ((int) → int). (dart:_interceptors/js_number.dart, line 349, col 13) +severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.& ((num) → num) is not a subtype of int.& ((int) → int). (dart:_interceptors/js_number.dart, line 349, col 13) severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.abs (() → num) is not a subtype of int.abs (() → int). (dart:_interceptors/js_number.dart, line 349, col 13) severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.unary- (() → num) is not a subtype of int.unary- (() → int). (dart:_interceptors/js_number.dart, line 349, col 13) severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.<< ((num) → num) is not a subtype of int.<< ((int) → int). (dart:_interceptors/js_number.dart, line 349, col 13) -severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.& ((num) → num) is not a subtype of int.& ((int) → int). (dart:_interceptors/js_number.dart, line 349, col 13) +severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.>> ((num) → num) is not a subtype of int.>> ((int) → int). (dart:_interceptors/js_number.dart, line 349, col 13) severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.| ((num) → num) is not a subtype of int.| ((int) → int). (dart:_interceptors/js_number.dart, line 349, col 13) severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.^ ((num) → num) is not a subtype of int.^ ((int) → int). (dart:_interceptors/js_number.dart, line 349, col 13) severe: [AnalyzerMessage] Classes cannot implement 'int' (dart:_interceptors/js_number.dart, line 349, col 41) severe: [AnalyzerMessage] Classes cannot implement 'double' (dart:_interceptors/js_number.dart, line 349, col 46) -severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.sign (() → num) is not a subtype of double.sign (() → double). (dart:_interceptors/js_number.dart, line 420, col 16) -severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.% ((num) → num) is not a subtype of double.% ((num) → double). (dart:_interceptors/js_number.dart, line 420, col 16) -severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.* ((num) → num) is not a subtype of double.* ((num) → double). (dart:_interceptors/js_number.dart, line 420, col 16) -severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.- ((num) → num) is not a subtype of double.- ((num) → double). (dart:_interceptors/js_number.dart, line 420, col 16) -severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.+ ((num) → num) is not a subtype of double.+ ((num) → double). (dart:_interceptors/js_number.dart, line 420, col 16) severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.unary- (() → num) is not a subtype of double.unary- (() → double). (dart:_interceptors/js_number.dart, line 420, col 16) -severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.abs (() → num) is not a subtype of double.abs (() → double). (dart:_interceptors/js_number.dart, line 420, col 16) +severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.sign (() → num) is not a subtype of double.sign (() → double). (dart:_interceptors/js_number.dart, line 420, col 16) severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.remainder ((num) → num) is not a subtype of double.remainder ((num) → double). (dart:_interceptors/js_number.dart, line 420, col 16) +severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.abs (() → num) is not a subtype of double.abs (() → double). (dart:_interceptors/js_number.dart, line 420, col 16) +severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.+ ((num) → num) is not a subtype of double.+ ((num) → double). (dart:_interceptors/js_number.dart, line 420, col 16) +severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.- ((num) → num) is not a subtype of double.- ((num) → double). (dart:_interceptors/js_number.dart, line 420, col 16) +severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.* ((num) → num) is not a subtype of double.* ((num) → double). (dart:_interceptors/js_number.dart, line 420, col 16) +severe: [InvalidMethodOverride] Base class introduces an invalid override. The type of JSNumber.% ((num) → num) is not a subtype of double.% ((num) → double). (dart:_interceptors/js_number.dart, line 420, col 16) severe: [AnalyzerMessage] Classes cannot implement 'double' (dart:_interceptors/js_number.dart, line 420, col 44) severe: [AnalyzerMessage] Classes cannot implement 'String' (dart:_interceptors/js_string.dart, line 14, col 47) severe: [StaticTypeError] Type check failed: s += s (String) is not of type JSString (dart:_interceptors/js_string.dart, line 346, col 7)