Remove diag::type_of_expression_is_ambiguous

This is a diagnostic that is only really emitted as a fallback when
the constraint system isn't able to better diagnose the expression.
It's not particulary helpful for the user, and can be often be
misleading since the underlying issue might not actually be an
ambiguity, and the user may well already have a type annotation. Let's
instead just emit the fallback diagnostic that we emit in all other
cases, asking the user to file a bug.
This commit is contained in:
Hamish Knight
2025-08-19 11:56:17 +01:00
parent a554080a82
commit 5c3f6703a0
21 changed files with 51 additions and 59 deletions

View File

@@ -4749,15 +4749,10 @@ ERROR(could_not_infer_pack_element,none,
NOTE(note_in_opening_pack_element,none, NOTE(note_in_opening_pack_element,none,
"in inferring pack element #%0 of '%1'", (unsigned,StringRef)) "in inferring pack element #%0 of '%1'", (unsigned,StringRef))
ERROR(type_of_expression_is_ambiguous,none,
"type of expression is ambiguous without a type annotation", ())
ERROR(failed_to_produce_diagnostic,none, ERROR(failed_to_produce_diagnostic,none,
"failed to produce diagnostic for expression; " "failed to produce diagnostic for expression; "
SWIFT_BUG_REPORT_MESSAGE, ()) SWIFT_BUG_REPORT_MESSAGE, ())
ERROR(missing_protocol,none, ERROR(missing_protocol,none,
"missing protocol %0", (Identifier)) "missing protocol %0", (Identifier))
ERROR(nil_literal_broken_proto,none, ERROR(nil_literal_broken_proto,none,

View File

@@ -4768,6 +4768,21 @@ void ConstraintSystem::diagnoseFailureFor(SyntacticElementTarget target) {
return; return;
} }
if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
auto *outerWrapper = wrappedVar->getOutermostAttachedPropertyWrapper();
Type propertyType = wrappedVar->getInterfaceType();
Type wrapperType = outerWrapper->getType();
// Emit the property wrapper fallback diagnostic
wrappedVar->diagnose(diag::property_wrapper_incompatible_property,
propertyType, wrapperType);
if (auto nominal = wrapperType->getAnyNominal()) {
nominal->diagnose(diag::property_wrapper_declared_here,
nominal->getName());
}
return;
}
if (auto expr = target.getAsExpr()) { if (auto expr = target.getAsExpr()) {
if (auto *assignment = dyn_cast<AssignExpr>(expr)) { if (auto *assignment = dyn_cast<AssignExpr>(expr)) {
if (isa<DiscardAssignmentExpr>(assignment->getDest())) if (isa<DiscardAssignmentExpr>(assignment->getDest()))
@@ -4785,33 +4800,12 @@ void ConstraintSystem::diagnoseFailureFor(SyntacticElementTarget target) {
.highlight(closure->getSourceRange()); .highlight(closure->getSourceRange());
return; return;
} }
// If no one could find a problem with this expression or constraint system,
// then it must be well-formed... but is ambiguous. Handle this by
// diagnostic various cases that come up.
DE.diagnose(expr->getLoc(), diag::type_of_expression_is_ambiguous)
.highlight(expr->getSourceRange());
} else if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
auto *outerWrapper = wrappedVar->getOutermostAttachedPropertyWrapper();
Type propertyType = wrappedVar->getInterfaceType();
Type wrapperType = outerWrapper->getType();
// Emit the property wrapper fallback diagnostic
wrappedVar->diagnose(diag::property_wrapper_incompatible_property,
propertyType, wrapperType);
if (auto nominal = wrapperType->getAnyNominal()) {
nominal->diagnose(diag::property_wrapper_declared_here,
nominal->getName());
}
} else if (target.getAsUninitializedVar()) {
DE.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic);
} else if (target.isForEachPreamble()) {
DE.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic);
} else {
// Emit a poor fallback message.
DE.diagnose(target.getAsFunction()->getLoc(),
diag::failed_to_produce_diagnostic);
} }
// Emit a poor fallback message.
auto diag = DE.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic);
if (auto *expr = target.getAsExpr())
diag.highlight(expr->getSourceRange());
} }
bool ConstraintSystem::isDeclUnavailable(const Decl *D, bool ConstraintSystem::isDeclUnavailable(const Decl *D,

View File

@@ -224,7 +224,7 @@ do {
// TODO(rdar://125948508): This shouldn't be ambiguous (@Sendable version should be preferred) // TODO(rdar://125948508): This shouldn't be ambiguous (@Sendable version should be preferred)
func test() -> KeyPath<String, Int> { func test() -> KeyPath<String, Int> {
true ? kp() : kp() // expected-error {{type of expression is ambiguous without a type annotation}} true ? kp() : kp() // expected-error {{failed to produce diagnostic for expression}}
} }
func forward<T>(_ v: T) -> T { v } func forward<T>(_ v: T) -> T { v }
@@ -249,7 +249,7 @@ do {
// TODO(rdar://125948508): This shouldn't be ambiguous (@Sendable version should be preferred) // TODO(rdar://125948508): This shouldn't be ambiguous (@Sendable version should be preferred)
func fnRet(cond: Bool) -> () -> Void { func fnRet(cond: Bool) -> () -> Void {
cond ? Test.fn : Test.otherFn // expected-error {{type of expression is ambiguous without a type annotation}} cond ? Test.fn : Test.otherFn // expected-error {{failed to produce diagnostic for expression}}
} }
func forward<T>(_: T) -> T { func forward<T>(_: T) -> T {

View File

@@ -290,7 +290,7 @@ func test_invalid_argument_to_keypath_subscript() {
// The diagnostic should point out that `ambiguous` is indeed ambiguous and that `5` is not a valid argument // The diagnostic should point out that `ambiguous` is indeed ambiguous and that `5` is not a valid argument
// for a key path subscript. // for a key path subscript.
ambiguous { ambiguous {
// expected-error@-1 {{type of expression is ambiguous without a type annotation}} // expected-error@-1 {{failed to produce diagnostic for expression}}
$0[keyPath: 5] $0[keyPath: 5]
} }

View File

@@ -285,7 +285,7 @@ func rdar60727310() {
// FIXME: Bad diagnostic. // FIXME: Bad diagnostic.
func f_54877(_ e: Error) { func f_54877(_ e: Error) {
func foo<T>(_ a: T, _ op: ((T, T) -> Bool)) {} func foo<T>(_ a: T, _ op: ((T, T) -> Bool)) {}
foo(e, ==) // expected-error {{type of expression is ambiguous without a type annotation}} foo(e, ==) // expected-error {{failed to produce diagnostic for expression}}
} }
// rdar://problem/62054241 - Swift compiler crashes when passing < as the sort function in sorted(by:) and the type of the array is not comparable // rdar://problem/62054241 - Swift compiler crashes when passing < as the sort function in sorted(by:) and the type of the array is not comparable

View File

@@ -8,7 +8,7 @@ protocol P<A> {
func f1(x: any P) -> any P<Int> { func f1(x: any P) -> any P<Int> {
// FIXME: Bad diagnostic // FIXME: Bad diagnostic
return x // expected-error {{type of expression is ambiguous without a type annotation}} return x // expected-error {{failed to produce diagnostic for expression}}
} }
func f2(x: any P<Int>) -> any P { func f2(x: any P<Int>) -> any P {
@@ -52,4 +52,4 @@ func h3(x: (any P<Int>)?) -> (any P<String>)? {
func generic1<T>(x: any P<T>) -> T { func generic1<T>(x: any P<T>) -> T {
return x.f() return x.f()
} }

View File

@@ -29,5 +29,5 @@ extension S4 where T == (outer: Int, y: Int) {
public func rdar85263844_2(_ x: [Int]) -> S4<(outer: Int, y: Int)> { public func rdar85263844_2(_ x: [Int]) -> S4<(outer: Int, y: Int)> {
// FIXME: Bad error message. // FIXME: Bad error message.
S4(x.map { (inner: $0, y: $0) }) // expected-error {{type of expression is ambiguous without a type annotation}} S4(x.map { (inner: $0, y: $0) }) // expected-error {{failed to produce diagnostic for expression}}
} }

View File

@@ -41,7 +41,7 @@ takesAnyObject()
takesAnyObject(C(), C(), C()) takesAnyObject(C(), C(), C())
// FIXME: Bad diagnostic // FIXME: Bad diagnostic
takesAnyObject(C(), S(), C()) // expected-error {{type of expression is ambiguous without a type annotation}} takesAnyObject(C(), S(), C()) // expected-error {{failed to produce diagnostic for expression}}
// Same-type requirements // Same-type requirements

View File

@@ -22,5 +22,5 @@ import Test;
public func test(_ _: AnyObject) {} public func test(_ _: AnyObject) {}
// TODO: make this a better error. // TODO: make this a better error.
test(Empty.create()) // expected-error {{type of expression is ambiguous without a type annotation}} test(Empty.create()) // expected-error {{failed to produce diagnostic for expression}}
test([Empty.create()][0]) // expected-error {{argument type 'Any' expected to be an instance of a class or class-constrained type}} test([Empty.create()][0]) // expected-error {{argument type 'Any' expected to be an instance of a class or class-constrained type}}

View File

@@ -21,4 +21,4 @@ func takesDeepNestedStruct(_ s: MyNS.MyDeepNS.DeepNestedStruct) {
} }
MyNS.method() // expected-error {{type 'MyNS' has no member 'method'}} MyNS.method() // expected-error {{type 'MyNS' has no member 'method'}}
MyNS.nestedMethod() // expected-error {{type of expression is ambiguous without a type annotation}} MyNS.nestedMethod() // expected-error {{failed to produce diagnostic for expression}}

View File

@@ -22,5 +22,5 @@ import namespaces;
// Swift's typechecker currently doesn't allow calling a function from inline namespace when it's referenced through the parent namespace. // Swift's typechecker currently doesn't allow calling a function from inline namespace when it's referenced through the parent namespace.
func test() { func test() {
Parent.functionInInlineChild() // expected-error {{type of expression is ambiguous without a type annotation}} Parent.functionInInlineChild() // expected-error {{failed to produce diagnostic for expression}}
} }

View File

@@ -99,7 +99,7 @@ struct File: ~Copyable {
discard (self) // expected-error {{cannot convert value of type 'File' to expected argument type 'Int'}} discard (self) // expected-error {{cannot convert value of type 'File' to expected argument type 'Int'}}
// FIXME: we should get an error about it being illegal to discard in a closure. // FIXME: we should get an error about it being illegal to discard in a closure.
let _ = { // expected-error {{type of expression is ambiguous without a type annotation}} let _ = { // expected-error {{failed to produce diagnostic for expression}}
discard self discard self
return 0 return 0
}() }()

View File

@@ -4,6 +4,6 @@ typealias Alias<T> = Int
func invalidSpecializeExpr(_ x: Alias<Int>.Type) { func invalidSpecializeExpr(_ x: Alias<Int>.Type) {
let y = x<Int>.self let y = x<Int>.self
// expected-error@-1 {{type of expression is ambiguous without a type annotation}} // expected-error@-1 {{failed to produce diagnostic for expression}}
// FIXME: Bad diagnostic // FIXME: Bad diagnostic
} }

View File

@@ -166,7 +166,7 @@ do {
// FIXME: Should GenericSignature::getConcreteType return the null type instead // FIXME: Should GenericSignature::getConcreteType return the null type instead
// of the error type here for Self.A, despite the broken conformance? // of the error type here for Self.A, despite the broken conformance?
let exist: any CompositionBrokenClassConformance_b & BadConformanceClass let exist: any CompositionBrokenClassConformance_b & BadConformanceClass
exist.method(false) // expected-error {{type of expression is ambiguous without a type annotation}} exist.method(false) // expected-error {{failed to produce diagnostic for expression}}
} }
// https://github.com/swiftlang/swift/issues/65533 // https://github.com/swiftlang/swift/issues/65533

View File

@@ -1,11 +1,14 @@
// RUN: %target-swift-frontend -typecheck %s -verify -verify-ignore-unknown // RUN: %target-swift-frontend -typecheck %s -verify -verify-ignore-unknown
// FIXME: This should produce a diagnostic with a proper // FIXME: This should produce a diagnostic with a proper
// source location. Right now, we just get three useless errors: // source location. Right now, we just get these errors:
// <unknown>:0: error: type of expression is ambiguous without a type annotation // <unknown>:0: error: cannot infer key path type from context; consider explicitly specifying a root type
// <unknown>:0: error: type of expression is ambiguous without a type annotation // <unknown>:0: error: cannot infer key path type from context; consider explicitly specifying a root type
// <unknown>:0: error: type of expression is ambiguous without a type annotation // <unknown>:0: error: cannot infer key path type from context; consider explicitly specifying a root type
// <unknown>:0: error: cannot infer key path type from context; consider explicitly specifying a root type
// <unknown>:0: error: cannot infer key path type from context; consider explicitly specifying a root type
// <unknown>:0: error: cannot infer key path type from context; consider explicitly specifying a root type
// The actual problem is the type of the subscript declaration is wrong. // The actual problem is the type of the subscript declaration is wrong.

View File

@@ -7,7 +7,7 @@ class Aaron {
func foo() { func foo() {
// Make sure we recover and assume 'self.init'. // Make sure we recover and assume 'self.init'.
// expected-error@+2 {{initializer expression requires explicit access; did you mean to prepend it with 'self.'?}} {{11-11=self.}} // expected-error@+2 {{initializer expression requires explicit access; did you mean to prepend it with 'self.'?}} {{11-11=self.}}
// expected-error@+1 {{type of expression is ambiguous without a type annotation}} // expected-error@+1 {{failed to produce diagnostic for expression}}
_ = init _ = init
} }
} }
@@ -48,7 +48,7 @@ class Theodosia: Aaron {
// Make sure we recover and assume 'self.init'. // Make sure we recover and assume 'self.init'.
// expected-error@+2 {{initializer expression requires explicit access; did you mean to prepend it with 'self.'?}} {{22-22=self.}} // expected-error@+2 {{initializer expression requires explicit access; did you mean to prepend it with 'self.'?}} {{22-22=self.}}
// expected-error@+1 {{type of expression is ambiguous without a type annotation}} // expected-error@+1 {{failed to produce diagnostic for expression}}
func foo() { _ = init } func foo() { _ = init }
} }

View File

@@ -510,7 +510,7 @@ do {
// FIXME: The type error is likely due to not solving the conjunction before attempting default type var bindings. // FIXME: The type error is likely due to not solving the conjunction before attempting default type var bindings.
let _ = (if .random() { Int?.none } else { 1 as Int? })?.bitWidth let _ = (if .random() { Int?.none } else { 1 as Int? })?.bitWidth
// expected-error@-1 {{type of expression is ambiguous without a type annotation}} // expected-error@-1 {{failed to produce diagnostic for expression}}
// expected-error@-2 {{'if' may only be used as expression in return, throw, or as the source of an assignment}} // expected-error@-2 {{'if' may only be used as expression in return, throw, or as the source of an assignment}}
} }
do { do {

View File

@@ -865,7 +865,7 @@ func test_keypath_with_method_refs() {
let _: KeyPath<S, (Int, Int) -> Int> = \.add() let _: KeyPath<S, (Int, Int) -> Int> = \.add()
// expected-error@-1 {{cannot assign value of type 'KeyPath<S, Int>' to type 'KeyPath<S, (Int, Int) -> Int>'}} // expected-error@-1 {{cannot assign value of type 'KeyPath<S, Int>' to type 'KeyPath<S, (Int, Int) -> Int>'}}
// expected-note@-2 {{arguments to generic parameter 'Value' ('Int' and '(Int, Int) -> Int') are expected to be equal}} // expected-note@-2 {{arguments to generic parameter 'Value' ('Int' and '(Int, Int) -> Int') are expected to be equal}}
let _: KeyPath<S, Int> = \.add() // expected-error {{type of expression is ambiguous without a type annotation}} let _: KeyPath<S, Int> = \.add() // expected-error {{failed to produce diagnostic for expression}}
let _: KeyPath<S, (Int) -> Int> = \.add(this:) let _: KeyPath<S, (Int) -> Int> = \.add(this:)
let _: KeyPath<S, Int> = \.add(that: 1) let _: KeyPath<S, Int> = \.add(that: 1)
let _: KeyPath<S, (Int) -> Int> = \.subtract // expected-error {{static member 'subtract' cannot be used on instance of type 'S'}} let _: KeyPath<S, (Int) -> Int> = \.subtract // expected-error {{static member 'subtract' cannot be used on instance of type 'S'}}
@@ -924,10 +924,10 @@ func test_keypath_with_method_refs() {
subscript(index: Int) -> Int { return index } subscript(index: Int) -> Int { return index }
} }
let _: KeyPath<A, Int> = \.foo.bar // expected-error {{type of expression is ambiguous without a type annotation}} let _: KeyPath<A, Int> = \.foo.bar // expected-error {{failed to produce diagnostic for expression}}
let _: KeyPath<A, Int> = \.faz.bar // expected-error {{static member 'faz()' cannot be used on instance of type 'A'}} let _: KeyPath<A, Int> = \.faz.bar // expected-error {{static member 'faz()' cannot be used on instance of type 'A'}}
let _ = \A.foo.bar // expected-error {{type of expression is ambiguous without a type annotation}} let _ = \A.foo.bar // expected-error {{failed to produce diagnostic for expression}}
let _ = \A.Type.faz.bar // expected-error {{type of expression is ambiguous without a type annotation}} let _ = \A.Type.faz.bar // expected-error {{failed to produce diagnostic for expression}}
let _: KeyPath<A, Int> = \.foo().bar let _: KeyPath<A, Int> = \.foo().bar
let _: KeyPath<A.Type, Int> = \.faz().bar let _: KeyPath<A.Type, Int> = \.faz().bar
let _ = \A.foo().bar let _ = \A.foo().bar

View File

@@ -670,7 +670,7 @@ do {
// FIXME: The type error is likely due to not solving the conjunction before attempting default type var bindings. // FIXME: The type error is likely due to not solving the conjunction before attempting default type var bindings.
let _ = (switch Bool.random() { case true: Int?.none case false: 1 })?.bitWidth let _ = (switch Bool.random() { case true: Int?.none case false: 1 })?.bitWidth
// expected-error@-1 {{type of expression is ambiguous without a type annotation}} // expected-error@-1 {{failed to produce diagnostic for expression}}
// expected-error@-2 {{'switch' may only be used as expression in return, throw, or as the source of an assignment}} // expected-error@-2 {{'switch' may only be used as expression in return, throw, or as the source of an assignment}}
} }
do { do {

View File

@@ -86,5 +86,5 @@ func testPrimaries(
takePrimaryCollections(setOfStrings, setOfInts) takePrimaryCollections(setOfStrings, setOfInts)
takePrimaryCollections(setOfStrings, arrayOfInts) takePrimaryCollections(setOfStrings, arrayOfInts)
_ = takeMatchedPrimaryCollections(arrayOfInts, setOfInts) _ = takeMatchedPrimaryCollections(arrayOfInts, setOfInts)
_ = takeMatchedPrimaryCollections(arrayOfInts, setOfStrings) // expected-error{{type of expression is ambiguous without a type annotation}} _ = takeMatchedPrimaryCollections(arrayOfInts, setOfStrings) // expected-error{{failed to produce diagnostic for expression}}
} }

View File

@@ -106,7 +106,7 @@ func testPrimaries(
takePrimaryCollections(setOfStrings, setOfInts) takePrimaryCollections(setOfStrings, setOfInts)
takePrimaryCollections(setOfStrings, arrayOfInts) takePrimaryCollections(setOfStrings, arrayOfInts)
_ = takeMatchedPrimaryCollections(arrayOfInts, setOfInts) _ = takeMatchedPrimaryCollections(arrayOfInts, setOfInts)
_ = takeMatchedPrimaryCollections(arrayOfInts, setOfStrings) // expected-error{{type of expression is ambiguous without a type annotation}} _ = takeMatchedPrimaryCollections(arrayOfInts, setOfStrings) // expected-error{{failed to produce diagnostic for expression}}
} }