-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Analyzer incorrectly applies an extension on a type-variable-typed expression, derived from an intersection type #53711
Comments
Noted in passing that @srujzs just ran into this bug. |
A few more details that may or may not be useful:
extension E<T extends Object> on T {
ExtType<T> get toExtType =>
ExtType<T>._(this);
}
extension type ExtType<T extends Object>._(T t) {}
class C<T> {
void consumeExtType(ExtType e) {}
void consumeT(T t) {
if (t != null) {
consumeExtType(t.toExtType);
}
}
}
Maybe displaying the intersection type makes it easier to understand than the current CFE error, but maybe that's even more confusing. |
We do have #56028, which is intended to elicit an answer to the underlying question. That is, "during extension method resolution on In this comment, I'm suggesting that the answer should be " The main motivation is that The main argument against this choice is that the return type of the extension member invocation, when based on a receiver type of extension<X> on X {
X get show {
print(this);
return this;
}
}
extension on int {
void get bar => 0;
}
void f<Y extends num>(Y y) {
if (y is int) {
// `y` has type `Y & int`.
Y y2 = y;
int i = y;
// If `y` has type `int` for extension matching
// then we do get `int` based extension members.
y.bar;
// We have `int` instance members, too, of course.
y.isEven;
// But if `y` has type `int` then we can't do this,
// because `y.show` has type `int`, too.
y2 = y.show;
}
} It would be nice to have all the affordances based on each of the operands of an intersection type, but we do have to choose an specific reified type to pass to the extension as the actual type argument at run time, and it isn't sound to use anything other than the type argument value which is actually passed when computing the type of the returned object. In any case, I think this issue is blocked on #56028. |
Hi! Some thoughts on this today, and through testing, just to help to narrow the problem. If you take the But interestingly, adding EditAm I sure to guess that all parameter types with definitions like |
Right, if both Making it extend |
Thanks for the docs, but I'm not completely sure they're right. Or at least that doesn't seem to be the case
It seems to me that it is resulting |
(Notice that this is not an extension, so the rules are not at all in question.) The inference of Then inference of It tries to find constraints for that based on the initial constraints of |
I think that's exactly what we're clarifying right here, and elsewhere. ;-) In particular, perhaps It follows that we have no idea whether |
No "perhaps" needed, that's how it's specified. Given: extension Apply<X> on X {
R apply<R>(R Function(X) function) => function(this);
}
void foo<T>(T value) {
if (foo is DateTime) {
String text = foo.apply((DateTime value) => value.toString());
}
} the applicability check (after seeing that it has an class Apply<T> {
Apply(T value);
} with no context type and If we can solving that for binding to the extension's type parameters, and then find that the instantiated That inference and instantiation of type parameters must erase The instantiated Then that invocation is rejected because |
Sure, that is exactly the reason why my example mentioned here contains a This, however, does not prevent us from using the intersection type during type inference, as long as the final result is a list of actual type arguments that satisfy all the constraints. Here is an example: X bar<X extends int>(X x1, X x2) {
print(x1.isEven);
return x1;
}
void foo<Y>(Y y) {
if (y is int) { // `y` has type `Y & int`.
// This invocation is inferred as `bar<int>(y, 24)`.
bar(y, 24);
}
}
void main() => foo<Object>(42); For the invocation of If we erase the type of So we can do that, but (1) it would be less powerful, and (2) the CFE doesn't do it currently, and it works correctly as far as I can see. I think this implies that we should not erase the intersection type before we start inferring the actual type arguments to the extension. But we must check that the required erasure at the end doesn't introduce any soundness issues. |
From @FMorschel at #52077:
@lrhn comments:
Originally posted by @lrhn in #52077 (comment)
The text was updated successfully, but these errors were encountered: