Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1207)

Unified Diff: pkg/analyzer/lib/src/task/strong/checker.dart

Issue 1834213002: Improve highlighting for strong mode error (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/task/strong/checker.dart
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 79da6a86d9c37d27a0e93d685adf97e9649d2b36..acffa08ca7cf4a39ee9e390b93ba03def36cd049 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -345,7 +345,8 @@ class CodeChecker extends RecursiveAstVisitor {
// supertype of it, do an implicit downcast to Iterable<dynamic>. Then
// we'll do a separate cast of the dynamic element to the variable's type.
if (elementType == null) {
- var sequenceType = sequenceInterface.instantiate([DynamicTypeImpl.instance]);
+ var sequenceType =
+ sequenceInterface.instantiate([DynamicTypeImpl.instance]);
if (rules.isSubtypeOf(sequenceType, iterableType)) {
_recordMessage(DownCast.create(
@@ -636,6 +637,55 @@ class CodeChecker extends RecursiveAstVisitor {
}
}
+ /// Records a [DownCast] of [expr] from [from] to [to], if there is one.
Bob Nystrom 2016/03/28 19:59:40 Are there changes to this, or did it just move? Is
Brian Wilkerson 2016/03/28 20:34:33 No, there are no changes. I was only expecting cha
+ ///
+ /// If [from] is omitted, uses the static type of [expr].
+ ///
+ /// If [expr] does not require a downcast because it is not related to [to]
+ /// or is already a subtype of it, does nothing.
+ void _checkDowncast(Expression expr, DartType to, {DartType from}) {
+ if (from == null) {
+ from = _getStaticType(expr);
+ }
+
+ // We can use anything as void.
+ if (to.isVoid) return;
+
+ // fromT <: toT, no coercion needed.
+ if (rules.isSubtypeOf(from, to)) return;
+
+ // TODO(vsm): We can get rid of the second clause if we disallow
+ // all sideways casts - see TODO below.
+ // -------
+ // Note: a function type is never assignable to a class per the Dart
+ // spec - even if it has a compatible call method. We disallow as
+ // well for consistency.
+ if ((from is FunctionType && rules.getCallMethodType(to) != null) ||
+ (to is FunctionType && rules.getCallMethodType(from) != null)) {
+ return;
+ }
+
+ // Downcast if toT <: fromT
+ if (rules.isSubtypeOf(to, from)) {
+ _recordMessage(DownCast.create(rules, expr, from, to));
+ return;
+ }
+
+ // TODO(vsm): Once we have generic methods, we should delete this
+ // workaround. These sideways casts are always ones we warn about
+ // - i.e., we think they are likely to fail at runtime.
+ // -------
+ // Downcast if toT <===> fromT
+ // The intention here is to allow casts that are sideways in the restricted
+ // type system, but allowed in the regular dart type system, since these
+ // are likely to succeed. The canonical example is List<dynamic> and
+ // Iterable<T> for some concrete T (e.g. Object). These are unrelated
+ // in the restricted system, but List<dynamic> <: Iterable<T> in dart.
+ if (from.isAssignableTo(to)) {
+ _recordMessage(DownCast.create(rules, expr, from, to));
+ }
+ }
+
void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) {
if ((_isDynamicTarget(target) || field.staticElement == null) &&
!_isObjectProperty(target, field)) {
@@ -646,7 +696,7 @@ class CodeChecker extends RecursiveAstVisitor {
void _checkReturnOrYield(Expression expression, AstNode node,
{bool yieldStar: false}) {
- var body = node.getAncestor((n) => n is FunctionBody);
+ FunctionBody body = node.getAncestor((n) => n is FunctionBody);
var type = _getExpectedReturnType(body, yieldStar: yieldStar);
if (type == null) {
// We have a type mismatch: the async/async*/sync* modifier does
@@ -687,55 +737,6 @@ class CodeChecker extends RecursiveAstVisitor {
}
}
- /// Records a [DownCast] of [expr] from [from] to [to], if there is one.
- ///
- /// If [from] is omitted, uses the static type of [expr].
- ///
- /// If [expr] does not require a downcast because it is not related to [to]
- /// or is already a subtype of it, does nothing.
- void _checkDowncast(Expression expr, DartType to, {DartType from}) {
- if (from == null) {
- from = _getStaticType(expr);
- }
-
- // We can use anything as void.
- if (to.isVoid) return;
-
- // fromT <: toT, no coercion needed.
- if (rules.isSubtypeOf(from, to)) return;
-
- // TODO(vsm): We can get rid of the second clause if we disallow
- // all sideways casts - see TODO below.
- // -------
- // Note: a function type is never assignable to a class per the Dart
- // spec - even if it has a compatible call method. We disallow as
- // well for consistency.
- if ((from is FunctionType && rules.getCallMethodType(to) != null) ||
- (to is FunctionType && rules.getCallMethodType(from) != null)) {
- return;
- }
-
- // Downcast if toT <: fromT
- if (rules.isSubtypeOf(to, from)) {
- _recordMessage(DownCast.create(rules, expr, from, to));
- return;
- }
-
- // TODO(vsm): Once we have generic methods, we should delete this
- // workaround. These sideways casts are always ones we warn about
- // - i.e., we think they are likely to fail at runtime.
- // -------
- // Downcast if toT <===> fromT
- // The intention here is to allow casts that are sideways in the restricted
- // type system, but allowed in the regular dart type system, since these
- // are likely to succeed. The canonical example is List<dynamic> and
- // Iterable<T> for some concrete T (e.g. Object). These are unrelated
- // in the restricted system, but List<dynamic> <: Iterable<T> in dart.
- if (from.isAssignableTo(to)) {
- _recordMessage(DownCast.create(rules, expr, from, to));
- }
- }
-
// Produce a coercion which coerces something of type fromT
// to something of type toT.
// Returns the error coercion if the types cannot be coerced
@@ -749,7 +750,8 @@ class CodeChecker extends RecursiveAstVisitor {
functionType = _elementType(parent.element);
} else {
assert(parent is FunctionExpression);
- functionType = parent.staticType ?? DynamicTypeImpl.instance;
+ functionType =
+ (parent as FunctionExpression).staticType ?? DynamicTypeImpl.instance;
}
var type = functionType.returnType;
@@ -804,55 +806,6 @@ class CodeChecker extends RecursiveAstVisitor {
return t;
}
- /// Remove "fuzzy arrow" in this function type.
- ///
- /// Normally we treat dynamically typed parameters as bottom for function
- /// types. This allows type tests such as `if (f is SingleArgFunction)`.
- /// It also requires a dynamic check on the parameter type to call these
- /// functions.
- ///
- /// When we convert to a strict arrow, dynamically typed parameters become
- /// top. This is safe to do for known functions, like top-level or local
- /// functions and static methods. Those functions must already be essentially
- /// treating dynamic as top.
- ///
- /// Only the outer-most arrow can be strict. Any others must be fuzzy, because
- /// we don't know what function value will be passed there.
- // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function
- // type? That would allow us to implement this in the subtype relation.
- // TODO(jmesserly): we'll need to factor this differently if we want to
- // move CodeChecker's functionality into existing analyzer. Likely we can
- // let the Expression have a strict arrow, then in places were we do
- // inference, convert back to a fuzzy arrow.
- FunctionType _removeFuzz(FunctionType t) {
- bool foundFuzz = false;
- List<ParameterElement> parameters = <ParameterElement>[];
- for (ParameterElement p in t.parameters) {
- ParameterElement newP = _removeParameterFuzz(p);
- parameters.add(newP);
- if (p != newP) foundFuzz = true;
- }
- if (!foundFuzz) {
- return t;
- }
-
- FunctionElementImpl function = new FunctionElementImpl("", -1);
- function.synthetic = true;
- function.returnType = t.returnType;
- function.shareTypeParameters(t.typeFormals);
- function.shareParameters(parameters);
- return function.type = new FunctionTypeImpl(function);
- }
-
- /// Removes fuzzy arrow, see [_removeFuzz].
- ParameterElement _removeParameterFuzz(ParameterElement p) {
- if (p.type.isDynamic) {
- return new ParameterElementImpl.synthetic(
- p.name, typeProvider.objectType, p.parameterKind);
- }
- return p;
- }
-
/// Given an expression, return its type assuming it is
/// in the caller position of a call (that is, accounting
/// for the possibility of a call method). Returns null
@@ -955,6 +908,55 @@ class CodeChecker extends RecursiveAstVisitor {
}
}
+ /// Remove "fuzzy arrow" in this function type.
+ ///
+ /// Normally we treat dynamically typed parameters as bottom for function
+ /// types. This allows type tests such as `if (f is SingleArgFunction)`.
+ /// It also requires a dynamic check on the parameter type to call these
+ /// functions.
+ ///
+ /// When we convert to a strict arrow, dynamically typed parameters become
+ /// top. This is safe to do for known functions, like top-level or local
+ /// functions and static methods. Those functions must already be essentially
+ /// treating dynamic as top.
+ ///
+ /// Only the outer-most arrow can be strict. Any others must be fuzzy, because
+ /// we don't know what function value will be passed there.
+ // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function
+ // type? That would allow us to implement this in the subtype relation.
+ // TODO(jmesserly): we'll need to factor this differently if we want to
+ // move CodeChecker's functionality into existing analyzer. Likely we can
+ // let the Expression have a strict arrow, then in places were we do
+ // inference, convert back to a fuzzy arrow.
+ FunctionType _removeFuzz(FunctionType t) {
+ bool foundFuzz = false;
+ List<ParameterElement> parameters = <ParameterElement>[];
+ for (ParameterElement p in t.parameters) {
+ ParameterElement newP = _removeParameterFuzz(p);
+ parameters.add(newP);
+ if (p != newP) foundFuzz = true;
+ }
+ if (!foundFuzz) {
+ return t;
+ }
+
+ FunctionElementImpl function = new FunctionElementImpl("", -1);
+ function.synthetic = true;
+ function.returnType = t.returnType;
+ function.shareTypeParameters(t.typeFormals);
+ function.shareParameters(parameters);
+ return function.type = new FunctionTypeImpl(function);
+ }
+
+ /// Removes fuzzy arrow, see [_removeFuzz].
+ ParameterElement _removeParameterFuzz(ParameterElement p) {
+ if (p.type.isDynamic) {
+ return new ParameterElementImpl.synthetic(
+ p.name, typeProvider.objectType, p.parameterKind);
+ }
+ return p;
+ }
+
DartType _specializedBinaryReturnType(
TokenType op, DartType t1, DartType t2, DartType normalReturnType) {
// This special cases binary return types as per 16.26 and 16.27 of the
@@ -1058,7 +1060,6 @@ class _OverrideChecker {
_checkIndividualOverridesFromClass(ClassDeclaration node,
InterfaceType baseType, Set<String> seen, bool isSubclass) {
for (var member in node.members) {
- if (member is ConstructorDeclaration) continue;
if (member is FieldDeclaration) {
if (member.isStatic) continue;
for (var variable in member.fields.variables) {
@@ -1068,21 +1069,21 @@ class _OverrideChecker {
var getter = element.getter;
var setter = element.setter;
bool found = _checkSingleOverride(
- getter, baseType, variable, member, isSubclass);
+ getter, baseType, variable.name, member, isSubclass);
if (!variable.isFinal &&
!variable.isConst &&
_checkSingleOverride(
- setter, baseType, variable, member, isSubclass)) {
+ setter, baseType, variable.name, member, isSubclass)) {
found = true;
}
if (found) seen.add(name);
}
- } else {
- if ((member as MethodDeclaration).isStatic) continue;
- var method = (member as MethodDeclaration).element;
+ } else if (member is MethodDeclaration) {
+ if (member.isStatic) continue;
+ var method = member.element;
if (seen.contains(method.name)) continue;
if (_checkSingleOverride(
- method, baseType, member, member, isSubclass)) {
+ method, baseType, member.name, member, isSubclass)) {
seen.add(method.name);
}
}
Bob Nystrom 2016/03/28 19:59:40 Maybe leave a comment or assert that the only rema
Brian Wilkerson 2016/03/28 20:34:33 I'll do that.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698