Adjust NNBD_TOP_MERGE such that void does not prevail
#824
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
I raised an issue in #793 about the nnbd mechanism for computing a member signature named
mwhere multiple most-specific member signatures namedmoccur in the direct superinterfaces, and the class itself does not declare a member namedm. Here is an example showing the main cases (with the member signature ofmin comments):The problem that this PR aims to resolve is that it is a breaking change, and not a useful one as far as I can see, to get so many situations where return types and parameter types are
void. The same issue arises at any level of nesting, so we'd have a similar example where the type ends up beingList<void>with the current nnbd rules, andList<Object?>with this PR.The breakage occurs in two ways:
voidrather thanObject?ordynamicthen an error is likely to occur whenever the returned value is used (another possible outcome is that some local variable now gets inferred typevoid, which may cause a similar problem when that variable is used).voidrather thanObject?ordynamicin a method declaration where the superinterfaces are used to infer the parameter type ('override inference'), the same problems arise as those with the return type, except that it affects all usages of said parameter.There is no guarantee that the pre-nnbd rules would choose any particular top type, because those rules used the textual order of the superinterfaces. But if that rule gave rise to the choice of a return or parameter type which was not
void, then it will be a breaking change if just one of the most specific member signatures (from any superinterface) hasvoid. So in that sense it is a breaking change, even though there can be cases where there is no breakage.This PR ensures that
voidwill only occur in a member signature namedmwhen all the direct superinterfaces that have a member signature namedmagree that this position in the signature should be the typevoid. If just one of them saysdynamicthendynamicprevails, and if just one of them saysObject?then it prevails over bothvoidanddynamic.This is meaningful relative to the return type. Let's say we can choose that
mreturnsvoid(that is, we use the current nnbd rules) orObject?(with this PR). In this case at least one superinterface promises thatmreturns a usable object, and then the current class should also return a usable object, hence the type should beObject?. Whenmis called and the static type is a superinterface wheremreturnsvoid, the caller assumes that the object should be discarded. But that's also allowed when the return type isObject?, so that client can use the invocation correctly as well.