diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 27675a08699d0..60f328e9fbd83 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -8750,7 +8750,36 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( return SolutionKind::Solved; } - return matchExistentialTypes(type, protocol, kind, flags, locator); + auto result = matchExistentialTypes(type, protocol, kind, flags, locator); + + if (shouldAttemptFixes() && result.isFailure()) { + auto *loc = getConstraintLocator(locator); + + ArrayRef path = loc->getPath(); + while (!path.empty()) { + if (!path.back().is()) + break; + + path = path.drop_back(); + } + + if (path.size() != loc->getPath().size()) { + loc = getConstraintLocator(loc->getAnchor(), path); + } + + ConstraintFix *fix = nullptr; + if (loc->isLastElement()) { + fix = AllowArgumentMismatch::create(*this, type, protocol, loc); + } else if (loc->isLastElement()) { + fix = ContextualMismatch::create(*this, type, protocol, loc); + } + + if (fix) { + return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; + } + } + + return result; } void ConstraintSystem::recordSynthesizedConformance( @@ -9124,6 +9153,13 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( continue; } + // Matching existentials could introduce constraints with `instance type` + // element at the end if the confirming type wasn't fully resolved. + if (path.back().is()) { + path.pop_back(); + continue; + } + break; } @@ -9217,7 +9253,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( } } - if (loc->isLastElement()) { + if (path.back().is()) { auto *fix = ContextualMismatch::create(*this, protocolTy, type, loc); if (!recordFix(fix)) return SolutionKind::Solved; @@ -9227,7 +9263,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( // for example to `AnyHashable`. if ((kind == ConstraintKind::ConformsTo || kind == ConstraintKind::NonisolatedConformsTo) && - loc->isLastElement()) { + path.back().is()) { auto *fix = AllowArgumentMismatch::create(*this, type, protocolTy, loc); return recordFix(fix, /*impact=*/2) ? SolutionKind::Error : SolutionKind::Solved; diff --git a/test/Constraints/existential_metatypes.swift b/test/Constraints/existential_metatypes.swift index 759f5fb69ec91..baa0eb0ebdfc9 100644 --- a/test/Constraints/existential_metatypes.swift +++ b/test/Constraints/existential_metatypes.swift @@ -120,16 +120,20 @@ func parameterizedExistentials() { pt = ppt // expected-error {{cannot assign value of type 'any PP4.Type' to type 'any P4.Type'}} } +// https://github.com/swiftlang/swift/issues/83991 + func testNestedMetatype() { struct S: P {} - func bar(_ x: T) -> T.Type { type(of: x) } - func foo(_ x: P.Type.Type) { } + func bar(_ x: T) -> T.Type { } + func metaBar(_ x: T) -> T.Type.Type { } + func foo1(_ x: P.Type) {} + func foo2(_ x: P.Type.Type) { } - // Make sure we don't crash. - foo(bar(S.self)) + foo1(bar(S.self)) // expected-error {{argument type 'S.Type' does not conform to expected type 'P'}} - // FIXME: Bad diagnostic - // https://github.com/swiftlang/swift/issues/83991 - foo(bar(0)) // expected-error {{failed to produce diagnostic for expression}} + // Make sure we don't crash. + foo2(bar(S.self)) + foo2(bar(0)) // expected-error {{cannot convert value of type 'Int' to expected argument type 'any P.Type'}} + foo2(metaBar(0)) // expected-error {{argument type 'Int' does not conform to expected type 'P'}} } diff --git a/test/Generics/inverse_generics.swift b/test/Generics/inverse_generics.swift index 1fff8abf1c9a9..fdf886c9065de 100644 --- a/test/Generics/inverse_generics.swift +++ b/test/Generics/inverse_generics.swift @@ -538,5 +538,5 @@ func testYap(_ y: Yapping) { protocol Veggie: ~Copyable {} func generalized(_ x: Any.Type) {} func testMetatypes(_ t: (any Veggie & ~Copyable).Type) { - generalized(t) // expected-error {{cannot convert value of type '(any Veggie & ~Copyable).Type' to expected argument type 'any Any.Type'}} + generalized(t) // expected-error {{argument type 'any Veggie & ~Copyable' does not conform to expected type 'Copyable'}} }