-
Notifications
You must be signed in to change notification settings - Fork 17.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
proposal: spec: disallow impossible interface-interface type assertions #38907
Comments
With generalized interfaces (which are not just constrained by methods, but also by types), we have a chance to address this without giving up backward compatibility. For instance, the following: func _[P interface {
~int
m()
}](x interface{ m(int) }) {
_ = x.(P) // should this be permitted?
} is currently permitted, but arguably it shouldn't: it's impossible that the dynamic type of For a type assertion
This can be simplified to: A type assertion |
@griesemer I am not sure. We are generally permissive of empty type sets, IIRC to avoid action at a distance. What would we do in the following case?
It seems that by your definition the assertion |
@findleyr So you're saying we should allow this because there's no point in raising an error here since this generic function cannot be instantiated ever (no type implements But if we (in a future version of Go) end up permitting generalized interfaces as variable types, we may want the restriction. For instance, even in non-generic Go we can have type S struct{}
func (S) m(int)
func _(x interface{ m() }) {
_ = x.(S) // invalid type assertion
} with an invalid type assertion; this is also "action at a distance". If we change the signature of So, to rephrase, the (future) rule might be: A type assertion |
Yes, it seems confusing that no error is otherwise raised for the generic function, except in this innocuous looking type assertion of an empty interface.
Considering this hypothetical future rule, it looks like the spec is strictly more complicated than it would be if we extended our exemption to all interfaces: "A type assertion x.(T) is valid if the intersection of the type sets of the type of x and T is not empty, or if T is an interface." Of course, the rule would be even simpler if we didn't have the exemption for plain interfaces in the first place, but we can't change that. This extra complexity in the spec has a real cost in terms of user understanding and tooling support. What benefit do we get to offset this complexity?
I would argue that type set calculations are much less transparent than method signatures. We can produce a very meaningful error message as to why the type assertion fails in that case (missing method or incorrect signature). It is easier for a user to consider the type set when doing an instantiation, versus when doing a type assertion on an empty interface value. In short, I don't think we should produce an error for type assertion expressions with an empty type set, if we don't produce an error for values with an empty type set. |
For the record, my personal preference is that these kinds of impossible cases should be rejected at run time and by static analyzers, not by the language itself or the compilers. This is because Go does permit conditional compilation via the use of build tags. It is reasonable for code to be impossible in some configurations and possible in others. Rejecting this code at build times complicates the use of build tags. The gain from blocking these cases in the compiler as opposed to reporting them in go vet is minimal. All just my opinion, of course. |
Putting on hold until we are ready to consider removing language features. |
Now that we have introduced a vet check for this (see #4483), once we use modules to select the language version, we should disallow impossible interface-interface type assertions.
A quick refresher: Given a variable
x
of type interfaceI1
with a methodm()
, and an interfaceI2
with a method of the same name but different signaturem(int)
, the type assertionx.(I2)
can never succeed because no value satisfyingI1
can also satisfyI2
. The compiler can statically detect that this type assertion makes no sense (it will always panic or return false).The text was updated successfully, but these errors were encountered: