From a554080a82f4a64aa11796254915edc0258793ea Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 19 Aug 2025 17:12:49 +0100 Subject: [PATCH 1/2] Make `failed_to_produce_diagnostic` non-fatal --- include/swift/AST/DiagnosticsSema.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 3b2dc0c0dc285..dbec9719aadaf 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4753,7 +4753,7 @@ NOTE(note_in_opening_pack_element,none, ERROR(type_of_expression_is_ambiguous,none, "type of expression is ambiguous without a type annotation", ()) -ERROR(failed_to_produce_diagnostic,Fatal, +ERROR(failed_to_produce_diagnostic,none, "failed to produce diagnostic for expression; " SWIFT_BUG_REPORT_MESSAGE, ()) From 5c3f6703a052d2806e91ff9811be3ed74f906334 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 19 Aug 2025 11:56:17 +0100 Subject: [PATCH 2/2] 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. --- include/swift/AST/DiagnosticsSema.def | 5 -- lib/Sema/ConstraintSystem.cpp | 46 ++++++++----------- test/Concurrency/sendable_keypaths.swift | 4 +- test/Constraints/keypath.swift | 2 +- test/Constraints/operator.swift | 2 +- .../parameterized_existentials.swift | 4 +- test/Constraints/rdar85263844_swift6.swift | 2 +- .../variadic_generic_constraints.swift | 2 +- .../foreign-reference/not-any-object.swift | 2 +- .../import-as-member-typechecker.swift | 2 +- ...nline-namespace-function-call-broken.swift | 2 +- test/Sema/discard.swift | 2 +- test/Sema/issue-74858.swift | 2 +- .../existential_member_access/concrete.swift | 2 +- test/decl/var/property_wrappers_invalid.swift | 11 +++-- test/expr/postfix/init/unqualified.swift | 4 +- test/expr/unary/if_expr.swift | 2 +- test/expr/unary/keypath/keypath.swift | 8 ++-- test/expr/unary/switch_expr.swift | 2 +- .../implicit_some/opaque_parameters.swift | 2 +- test/type/opaque_parameters.swift | 2 +- 21 files changed, 51 insertions(+), 59 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index dbec9719aadaf..8c64d4073c461 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4749,15 +4749,10 @@ ERROR(could_not_infer_pack_element,none, NOTE(note_in_opening_pack_element,none, "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, "failed to produce diagnostic for expression; " SWIFT_BUG_REPORT_MESSAGE, ()) - ERROR(missing_protocol,none, "missing protocol %0", (Identifier)) ERROR(nil_literal_broken_proto,none, diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 95784054690d7..97e8debcacb53 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -4768,6 +4768,21 @@ void ConstraintSystem::diagnoseFailureFor(SyntacticElementTarget target) { 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 *assignment = dyn_cast(expr)) { if (isa(assignment->getDest())) @@ -4785,33 +4800,12 @@ void ConstraintSystem::diagnoseFailureFor(SyntacticElementTarget target) { .highlight(closure->getSourceRange()); 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, diff --git a/test/Concurrency/sendable_keypaths.swift b/test/Concurrency/sendable_keypaths.swift index b4e4f7b2ef0ea..b7081e8f2435c 100644 --- a/test/Concurrency/sendable_keypaths.swift +++ b/test/Concurrency/sendable_keypaths.swift @@ -224,7 +224,7 @@ do { // TODO(rdar://125948508): This shouldn't be ambiguous (@Sendable version should be preferred) func test() -> KeyPath { - 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(_ v: T) -> T { v } @@ -249,7 +249,7 @@ do { // TODO(rdar://125948508): This shouldn't be ambiguous (@Sendable version should be preferred) 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 { diff --git a/test/Constraints/keypath.swift b/test/Constraints/keypath.swift index a0627f847e2e3..312e3e32993e1 100644 --- a/test/Constraints/keypath.swift +++ b/test/Constraints/keypath.swift @@ -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 // for a key path subscript. 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] } diff --git a/test/Constraints/operator.swift b/test/Constraints/operator.swift index d199f88c65357..66f7725788f1d 100644 --- a/test/Constraints/operator.swift +++ b/test/Constraints/operator.swift @@ -285,7 +285,7 @@ func rdar60727310() { // FIXME: Bad diagnostic. func f_54877(_ e: Error) { func foo(_ 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 diff --git a/test/Constraints/parameterized_existentials.swift b/test/Constraints/parameterized_existentials.swift index 3151c158fc42f..ba0206e251037 100644 --- a/test/Constraints/parameterized_existentials.swift +++ b/test/Constraints/parameterized_existentials.swift @@ -8,7 +8,7 @@ protocol P { func f1(x: any P) -> any P { // 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) -> any P { @@ -52,4 +52,4 @@ func h3(x: (any P)?) -> (any P)? { func generic1(x: any P) -> T { return x.f() -} \ No newline at end of file +} diff --git a/test/Constraints/rdar85263844_swift6.swift b/test/Constraints/rdar85263844_swift6.swift index eb5e9d605443f..709aa109c8212 100644 --- a/test/Constraints/rdar85263844_swift6.swift +++ b/test/Constraints/rdar85263844_swift6.swift @@ -29,5 +29,5 @@ extension S4 where T == (outer: Int, y: Int) { public func rdar85263844_2(_ x: [Int]) -> S4<(outer: Int, y: Int)> { // 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}} } diff --git a/test/Constraints/variadic_generic_constraints.swift b/test/Constraints/variadic_generic_constraints.swift index f63214da2bb0f..aad4675bca27c 100644 --- a/test/Constraints/variadic_generic_constraints.swift +++ b/test/Constraints/variadic_generic_constraints.swift @@ -41,7 +41,7 @@ takesAnyObject() takesAnyObject(C(), C(), C()) // 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 diff --git a/test/Interop/Cxx/foreign-reference/not-any-object.swift b/test/Interop/Cxx/foreign-reference/not-any-object.swift index af3899f99967a..e79810cdeb27d 100644 --- a/test/Interop/Cxx/foreign-reference/not-any-object.swift +++ b/test/Interop/Cxx/foreign-reference/not-any-object.swift @@ -22,5 +22,5 @@ import Test; public func test(_ _: AnyObject) {} // 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}} diff --git a/test/Interop/Cxx/namespace/import-as-member-typechecker.swift b/test/Interop/Cxx/namespace/import-as-member-typechecker.swift index 79657309cff3e..5fe52f082971d 100644 --- a/test/Interop/Cxx/namespace/import-as-member-typechecker.swift +++ b/test/Interop/Cxx/namespace/import-as-member-typechecker.swift @@ -21,4 +21,4 @@ func takesDeepNestedStruct(_ s: MyNS.MyDeepNS.DeepNestedStruct) { } 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}} diff --git a/test/Interop/Cxx/namespace/inline-namespace-function-call-broken.swift b/test/Interop/Cxx/namespace/inline-namespace-function-call-broken.swift index 93606f6d589f0..0debaeed63c4a 100644 --- a/test/Interop/Cxx/namespace/inline-namespace-function-call-broken.swift +++ b/test/Interop/Cxx/namespace/inline-namespace-function-call-broken.swift @@ -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. 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}} } diff --git a/test/Sema/discard.swift b/test/Sema/discard.swift index 62cc50ce9db53..6896b8732a09b 100644 --- a/test/Sema/discard.swift +++ b/test/Sema/discard.swift @@ -99,7 +99,7 @@ struct File: ~Copyable { 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. - let _ = { // expected-error {{type of expression is ambiguous without a type annotation}} + let _ = { // expected-error {{failed to produce diagnostic for expression}} discard self return 0 }() diff --git a/test/Sema/issue-74858.swift b/test/Sema/issue-74858.swift index 2c202b35ca1e1..1af06195f9c4b 100644 --- a/test/Sema/issue-74858.swift +++ b/test/Sema/issue-74858.swift @@ -4,6 +4,6 @@ typealias Alias = Int func invalidSpecializeExpr(_ x: Alias.Type) { let y = x.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 } diff --git a/test/decl/protocol/existential_member_access/concrete.swift b/test/decl/protocol/existential_member_access/concrete.swift index 1cd4e4247a136..22868aa804e85 100644 --- a/test/decl/protocol/existential_member_access/concrete.swift +++ b/test/decl/protocol/existential_member_access/concrete.swift @@ -166,7 +166,7 @@ do { // FIXME: Should GenericSignature::getConcreteType return the null type instead // of the error type here for Self.A, despite the broken conformance? 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 diff --git a/test/decl/var/property_wrappers_invalid.swift b/test/decl/var/property_wrappers_invalid.swift index f6b351557598c..c228e83ed69a0 100644 --- a/test/decl/var/property_wrappers_invalid.swift +++ b/test/decl/var/property_wrappers_invalid.swift @@ -1,11 +1,14 @@ // RUN: %target-swift-frontend -typecheck %s -verify -verify-ignore-unknown // 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: -// :0: error: type of expression is ambiguous without a type annotation -// :0: error: type of expression is ambiguous without a type annotation -// :0: error: type of expression is ambiguous without a type annotation +// :0: error: cannot infer key path type from context; consider explicitly specifying a root type +// :0: error: cannot infer key path type from context; consider explicitly specifying a root type +// :0: error: cannot infer key path type from context; consider explicitly specifying a root type +// :0: error: cannot infer key path type from context; consider explicitly specifying a root type +// :0: error: cannot infer key path type from context; consider explicitly specifying a root type +// :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. diff --git a/test/expr/postfix/init/unqualified.swift b/test/expr/postfix/init/unqualified.swift index bb8372378d2c2..9a9824b40e166 100644 --- a/test/expr/postfix/init/unqualified.swift +++ b/test/expr/postfix/init/unqualified.swift @@ -7,7 +7,7 @@ class Aaron { func foo() { // 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@+1 {{type of expression is ambiguous without a type annotation}} + // expected-error@+1 {{failed to produce diagnostic for expression}} _ = init } } @@ -48,7 +48,7 @@ class Theodosia: Aaron { // 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@+1 {{type of expression is ambiguous without a type annotation}} + // expected-error@+1 {{failed to produce diagnostic for expression}} func foo() { _ = init } } diff --git a/test/expr/unary/if_expr.swift b/test/expr/unary/if_expr.swift index 7ecca30167ab5..50aa0562fc409 100644 --- a/test/expr/unary/if_expr.swift +++ b/test/expr/unary/if_expr.swift @@ -510,7 +510,7 @@ do { // 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 - // 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}} } do { diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index e58cbe6f79a37..16f5ff471b94a 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -865,7 +865,7 @@ func test_keypath_with_method_refs() { let _: KeyPath Int> = \.add() // expected-error@-1 {{cannot assign value of type 'KeyPath' to type 'KeyPath Int>'}} // expected-note@-2 {{arguments to generic parameter 'Value' ('Int' and '(Int, Int) -> Int') are expected to be equal}} - let _: KeyPath = \.add() // expected-error {{type of expression is ambiguous without a type annotation}} + let _: KeyPath = \.add() // expected-error {{failed to produce diagnostic for expression}} let _: KeyPath Int> = \.add(this:) let _: KeyPath = \.add(that: 1) let _: KeyPath 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 } } - let _: KeyPath = \.foo.bar // expected-error {{type of expression is ambiguous without a type annotation}} + let _: KeyPath = \.foo.bar // expected-error {{failed to produce diagnostic for expression}} let _: KeyPath = \.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.Type.faz.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 {{failed to produce diagnostic for expression}} let _: KeyPath = \.foo().bar let _: KeyPath = \.faz().bar let _ = \A.foo().bar diff --git a/test/expr/unary/switch_expr.swift b/test/expr/unary/switch_expr.swift index 3f976d53deaa6..c2e8e48467ef2 100644 --- a/test/expr/unary/switch_expr.swift +++ b/test/expr/unary/switch_expr.swift @@ -670,7 +670,7 @@ do { // 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 - // 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}} } do { diff --git a/test/type/implicit_some/opaque_parameters.swift b/test/type/implicit_some/opaque_parameters.swift index 999352133fa70..15514343c41d1 100644 --- a/test/type/implicit_some/opaque_parameters.swift +++ b/test/type/implicit_some/opaque_parameters.swift @@ -86,5 +86,5 @@ func testPrimaries( takePrimaryCollections(setOfStrings, setOfInts) takePrimaryCollections(setOfStrings, arrayOfInts) _ = 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}} } diff --git a/test/type/opaque_parameters.swift b/test/type/opaque_parameters.swift index a848269a7c4ad..99beb29d3c615 100644 --- a/test/type/opaque_parameters.swift +++ b/test/type/opaque_parameters.swift @@ -106,7 +106,7 @@ func testPrimaries( takePrimaryCollections(setOfStrings, setOfInts) takePrimaryCollections(setOfStrings, arrayOfInts) _ = 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}} }