Fixits for "Ambiguous use of ___" errors


(David Sweeris) #1

Something @Jens said in Higher order functions and function types in Swift reminded me of something...

For years, I've been thinking that It'd be great if Ambiguous use of <whatever> errors had a fixit for each candidate that'd resolve the ambiguity. The obvious reason is that it'd make life easier for developers. However, beyond that, in this particular case @Jens has come across a compiler bug because the code isn't ambiguous. Having the compiler generate disambiguation code for itself is something that can be tested against and possibly flag weird compiler bugs such as this one.

There is the question of the possibility of, um, "undisambiguable" code... for instance, if I add this function:

func + (lhs: Int, rhs: Int) -> Int { return lhs.addingReportingOverflow(rhs).partialValue }

to an existing codebase, then this line

var leadingZeroBitCount: Int { return value.leadingZeroBitCount - UInt8.bitWidth + SubUInt.bitWidth }

becomes ambiguous. However, changing the newly offending + to either Foundation.+ or Swift.+ results in Use of unresolved operator '.+' and Consecutive statements on a line must be separated by ';' errors (as well as a Expression of type 'Int' is unused warning).

I'm not sure how to best resolve such a situation... Is this a hole in the language or am I just not aware of the correct disambiguation syntax? I'm assuming that the function definition itself isn't an error, but I suppose that's a possibility as well.

Anyway, aside from that issue, I don't know how hard this would be to implement, but if it's something that the community seems interested in, I'd be happy to at least start working on it.


(Xiaodi Wu) #2

It is not possible to disambiguate at present. Although for compatibility reasons you can add such an operator function without using an extension, you should think of it like any other occasion on which you extend a type you don't own by means of an extension. Even when no ambiguity arises because of shadowing, the behavior can get confusing if there's more than one implementation, and there isn't really any way to refer to an implementation in one extension and not another.

It's fine to wonder if some grammar could be added to disambiguate explicitly, but in general I'd argue it's a code smell when functions start to step on each other like that, and on that basis the present state of things isn't really much of an issue because users who extend types they don't own are choosing to assume the complications that can arise from doing so. I think it'd be higher yield to look into the somewhat similar issue facing 'Result' today conflicting with third-party 'Result' types, which is bound to repeat itself in the future and is a situation where the third party is working entirely with its own types.


(David Sweeris) #3

Bummer, oh well. Wait, you're just talking about operators, right? I could've sworn that free functions, types, etc could be disambiguated like that, but I don't think I've ever needed to do it, so maybe I'm confused.

Agreed WRT the code smell. I will say, though, that the vast majority of the times I've unexpectedly gotten that error (when it wasn't a compiler bug, anyway), I'd wanted to know how to write the code unambiguously so that I could more easily figure out where my own protocols, conformances, and constraints were getting a bit too hand-wavy. That is, I was looking for help in making my code less smelly. Perhaps my assumption that such information would help is incorrect, though.

The problem I'm having is that everything I can think of (except the emergency fallback contingency of throwing a warning for enums named Result with one or two generic parameters in projects that aren't the standard library) would be a feature that I'd like to have in general, not as a special case to handle the fallout from adding a commonly used/requested type. Is there a thread for discussing this yet?