Fixits for "Ambiguous use of ___" errors

Something @Jens said in Higher order functions and function types in Swift - #4 by jrose 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.

1 Like

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.

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?

What about things like: Ambiguous use of 'toolbar(content:)'? The parsers inability to interact with the type system and provide conclusive error messaging is quite frustrating. There is little way to actually figure out what's going on here without commenting out blocks and messing with stuff that should just not be necessary.

The actual problem is below this in a .sheet() section where the values passed do not meet the type requirements in the view constructed in the .sheet(){} block. Type conflicts for arguments repeatedly perform in this way and I just don't understand how the .toolbar() block could possibly become the block context of the error when .sheet(){} is at the same level.

Hi @greggwon

This thread is six years old and SwiftUI wasn't even released until the following summer, so for sure we weren't talking about those APIs. Perhaps if there is some present issue you're noticing, it'd be best to start a new thread?

If the same error message is in the compiler 6 years later, it's likely related to a basic attribute of the compiler. Since it's a recursive descent parser, it's most likely related to the ambiguous nature of not having a statement terminator, like ';' in all places where blocks are not defined by {} pairs. This is the number one issue with free form language design. Any statement can be classified as a part of the previous statement but a '.' was not typed where needed. If, instead, ';' was being mandated by the language, the compiler would have a much easier time understanding to reduce instead of to keep shifting looking for something that is unambiguous.

In place of opening a new line, I ask here. I'm sorry.

In my case i get this error in the following line:

.background(
                .background
                    .shadow(.drop(color: .primary.opacity(0.08), radius: 5, x: 5, y: 5))
                    .shadow(.drop(color: .primary.opacity(0.06), radius: 5, x: -5, y: -5)),
                in: .capsule
            )

I can't find the meaning of this error, could someone help me? I'm adapting to Swiftui.