Index: pkg/compiler/lib/src/js_backend/no_such_method_registry.dart |
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart |
index e14a90b27be0b4eec4b6507cbf03ce9d39c82c0e..6502d42f02335e5a4f50d6d9be84dc6f5000b5f8 100644 |
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart |
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart |
@@ -4,10 +4,11 @@ |
import '../common.dart'; |
import '../common/names.dart' show Identifiers, Names, Selectors; |
-import '../compiler.dart' show Compiler; |
+import '../common_elements.dart'; |
import '../elements/elements.dart'; |
+import '../types/types.dart'; |
import '../tree/tree.dart'; |
-import 'backend.dart'; |
+import 'backend_helpers.dart'; |
/** |
* Categorizes `noSuchMethod` implementations. |
@@ -68,14 +69,10 @@ class NoSuchMethodRegistry { |
/// The implementations that have not yet been categorized. |
final Set<MethodElement> _uncategorizedImpls = new Set<MethodElement>(); |
- final JavaScriptBackend _backend; |
- final Compiler _compiler; |
+ final BackendHelpers _helpers; |
+ final NoSuchMethodResolver _resolver; |
- NoSuchMethodRegistry(JavaScriptBackend backend) |
- : this._backend = backend, |
- this._compiler = backend.compiler; |
- |
- DiagnosticReporter get reporter => _compiler.reporter; |
+ NoSuchMethodRegistry(this._helpers, this._resolver); |
bool get hasThrowingNoSuchMethod => throwingImpls.isNotEmpty; |
bool get hasComplexNoSuchMethod => otherImpls.isNotEmpty; |
@@ -92,24 +89,30 @@ class NoSuchMethodRegistry { |
/// Now that type inference is complete, split category D into two |
/// subcategories: D1, those that have no return type, and D2, those |
/// that have a return type. |
- void onTypeInferenceComplete() { |
- otherImpls.forEach(_subcategorizeOther); |
+ void onTypeInferenceComplete(GlobalTypeInferenceResults results) { |
+ otherImpls.forEach((MethodElement element) { |
+ if (results.resultOf(element).throwsAlways) { |
+ complexNoReturnImpls.add(element); |
+ } else { |
+ complexReturningImpls.add(element); |
+ } |
+ }); |
} |
/// Emits a diagnostic |
- void emitDiagnostic() { |
+ void emitDiagnostic(DiagnosticReporter reporter) { |
throwingImpls.forEach((e) { |
- if (!_hasForwardingSyntax(e)) { |
+ if (!_resolver.hasForwardingSyntax(e)) { |
reporter.reportHintMessage(e, MessageKind.DIRECTLY_THROWING_NSM); |
} |
}); |
complexNoReturnImpls.forEach((e) { |
- if (!_hasForwardingSyntax(e)) { |
+ if (!_resolver.hasForwardingSyntax(e)) { |
reporter.reportHintMessage(e, MessageKind.COMPLEX_THROWING_NSM); |
} |
}); |
complexReturningImpls.forEach((e) { |
- if (!_hasForwardingSyntax(e)) { |
+ if (!_resolver.hasForwardingSyntax(e)) { |
reporter.reportHintMessage(e, MessageKind.COMPLEX_RETURNING_NSM); |
} |
}); |
@@ -123,14 +126,6 @@ class NoSuchMethodRegistry { |
return otherImpls.contains(element); |
} |
- _subcategorizeOther(MethodElement element) { |
- if (_compiler.globalInference.results.resultOf(element).throwsAlways) { |
- complexNoReturnImpls.add(element); |
- } else { |
- complexReturningImpls.add(element); |
- } |
- } |
- |
NsmCategory _categorizeImpl(MethodElement element) { |
assert(element.name == Identifiers.noSuchMethod_); |
if (defaultImpls.contains(element)) { |
@@ -149,10 +144,10 @@ class NoSuchMethodRegistry { |
notApplicableImpls.add(element); |
return NsmCategory.NOT_APPLICABLE; |
} |
- if (isDefaultNoSuchMethodImplementation(element)) { |
+ if (_helpers.isDefaultNoSuchMethodImplementation(element)) { |
defaultImpls.add(element); |
return NsmCategory.DEFAULT; |
- } else if (_hasForwardingSyntax(element)) { |
+ } else if (_resolver.hasForwardingSyntax(element)) { |
// If the implementation is 'noSuchMethod(x) => super.noSuchMethod(x);' |
// then it is in the same category as the super call. |
Element superCall = |
@@ -176,7 +171,7 @@ class NoSuchMethodRegistry { |
break; |
} |
return category; |
- } else if (_hasThrowingSyntax(element)) { |
+ } else if (_resolver.hasThrowingSyntax(element)) { |
throwingImpls.add(element); |
return NsmCategory.THROWING; |
} else { |
@@ -184,15 +179,33 @@ class NoSuchMethodRegistry { |
return NsmCategory.OTHER; |
} |
} |
+} |
- bool isDefaultNoSuchMethodImplementation(MethodElement element) { |
- ClassElement classElement = element.enclosingClass; |
- return classElement == _compiler.commonElements.objectClass || |
- classElement == _backend.helpers.jsInterceptorClass || |
- classElement == _backend.helpers.jsNullClass; |
- } |
+enum NsmCategory { |
+ DEFAULT, |
+ THROWING, |
+ NOT_APPLICABLE, |
+ OTHER, |
+} |
+ |
+/// Interface for determining the form of a `noSuchMethod` implementation. |
+abstract class NoSuchMethodResolver { |
+ /// Computes whether [method] is of the form |
+ /// |
+ /// noSuchMethod(i) => super.noSuchMethod(i); |
+ /// |
+ bool hasForwardingSyntax(MethodElement method); |
- bool _hasForwardingSyntax(MethodElement element) { |
+ /// Computes whether [method] is of the form |
+ /// |
+ /// noSuchMethod(i) => throw new Error(); |
+ /// |
+ bool hasThrowingSyntax(MethodElement method); |
+} |
+ |
+/// AST-based implementation of [NoSuchMethodResolver]. |
+class NoSuchMethodResolverImpl implements NoSuchMethodResolver { |
+ bool hasForwardingSyntax(MethodElement element) { |
// At this point we know that this is signature-compatible with |
// Object.noSuchMethod, but it may have more than one argument as long as |
// it only has one required argument. |
@@ -242,7 +255,7 @@ class NoSuchMethodRegistry { |
return false; |
} |
- bool _hasThrowingSyntax(MethodElement element) { |
+ bool hasThrowingSyntax(MethodElement element) { |
if (!element.hasResolvedAst) { |
// TODO(johnniwinther): Why do we see unresolved elements here? |
return false; |
@@ -267,10 +280,3 @@ class NoSuchMethodRegistry { |
return false; |
} |
} |
- |
-enum NsmCategory { |
- DEFAULT, |
- THROWING, |
- NOT_APPLICABLE, |
- OTHER, |
-} |