-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Unsound implicit cast when using conditional expression #27922
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The problem here is that the least upper ound of @leafpetersen, @lrhn, @eernstg: is this a duplicate of our LUB bug #27525, or does this fall into the partial/raw type category, or is this just a bug in the analyzer? |
forgot @munificent |
I can't see if this is strong-mode or not. I'm guessing where this is coming from, so it probably is. If not, then the actual types of the conditional expression are:
These two type expansions have nothing in common except Object. If it is strong mode, I'm not absolutely sure how types will be inferred for the I don't think it's an analyzer bug. |
Yeah, I forgot to mention. This is strong mode. No complaints from the analyzer in "weak" mode. I can bind the type parameters further (in an attempt to please the analyzer -- an class Fisk<D> {}
class LinearFisk extends Fisk<double> {}
class OrdinalFisk extends Fisk<double> {}
class Hest<D, S extends Fisk<D>> {}
class OrdinalHest extends Hest<double, OrdinalFisk> {}
class NumericHest extends Hest<double, LinearFisk> {}
void main() {
final check = true;
// Fails: Unsound implicit cast from Object to Hest<double, Fisk<double>>
Hest<double, Fisk<double>> hest = check ? new OrdinalHest() : new NumericHest();
// No errors reported in the code below.
if (check) {
hest = new OrdinalHest();
} else {
hest = new NumericHest();
}
} Still no luck. The problem (or feature as designed?) is the second type parameter. If I put in I can probably structure the code in another way to work around this, but it goes against my intuition that the conditional expression and if-else should behave the same way in this case, so I thought I'd file this issue. |
Just trying it out shows that you only get the message (with dartanalyzer version 1.21.0-dev.9.0) in strong mode, and the message comes from That message is used for the errors DOWN_CAST_COMPOSITE, DOWN_CAST_IMPLICIT, DOWN_CAST_IMPLICIT_ASSIGN, DYNAMIC_CAST, and ASSIGNMENT_CAST, and it turned out to be DOWN_CAST_COMPOSITE in this case. That case is chosen by the following code in lib/src/task/strong/checker.dart: // Composite cast: these are more likely to fail.
bool downCastComposite = false;
if (!rules.isGroundType(to)) {
// This cast is (probably) due to our different treatment of dynamic.
// It may be more likely to fail at runtime.
if (from is InterfaceType) {
// For class types, we'd like to allow non-generic down casts, e.g.,
// Iterable<T> to List<T>. The intuition here is that raw (generic)
// casts are problematic, and we should complain about those.
var typeArgs = from.typeArguments;
downCastComposite =
typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic);
} else {
downCastComposite = !from.isDynamic;
}
} In this case we have bool isGroundType(DartType t) {
// TODO(leafp): Revisit this.
if (t is TypeParameterType) {
return false;
}
if (_isTop(t)) {
return true;
}
if (t is FunctionType) {
if (!_isTop(t.returnType) ||
anyParameterType(t, (pt) => !_isBottom(pt, dynamicIsBottom: true))) {
return false;
} else {
return true;
}
}
if (t is InterfaceType) {
List<DartType> typeArguments = t.typeArguments;
for (DartType typeArgument in typeArguments) {
if (!_isTop(typeArgument)) return false;
}
return true;
}
// We should not see any other type aside from malformed code.
return false;
} So I guess |
With the 2nd version of the program you gave, the conditional expression will then have type |
This is a least upper bound issue. Strong mode (in this case) is using the spec version of least upper bound, and the spec definition gives class OrdinalHest extends Hest<double, Fisk> {}
class NumericHest extends Hest<double, Fisk> {} then the spec mode (and hence the strong mode as well) least upper bound of I believe that the proposal that I made for replacing spec mode least upper bound in strong mode would do the right thing for this example (both variants). |
I'd think that there is an issue which has nothing to do with least upper bounds. The program doesn't need to contain any conditional expressions at all, and we can still get "Unsafe implicit cast from 'Object' to 'Hest<Object, Fisk>'" from class Fisk<D> {}
class Hest<D, S extends Fisk<D>> {}
void main() {
Hest<Object, Fisk<Object>> hest = null as Object; // Warning here.
} Of course, it is always safe to warn about a problem that may or may not be there. But I believe that we cannot have an instance of |
The unsafe implicit downcast warning exists in strong mode to help users transition from non-strong mode platforms. As strong mode becomes more broadly supported, I think we should just eliminate this warning. |
The implicit cast warning is no longer on by default, and the least upper bound issues are tracked separately. Closing this one. |
dartanalyzer version 1.21.0-dev.3.0
The analyzer complains about the conditional expression in the code below: [warning] Unsound implicit cast from 'Object' to 'Hest<dynamic, Fisk>'.
No complaints for the if-else.
The text was updated successfully, but these errors were encountered: