Skip to content

[Diagnostics] Remove argument handling from conformance failures #27660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 2 additions & 46 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,26 +542,11 @@ void RequirementFailure::emitRequirementNote(const Decl *anchor, Type lhs,

bool MissingConformanceFailure::diagnoseAsError() {
auto *anchor = getAnchor();
auto ownerType = getOwnerType();
auto nonConformingType = getLHS();
auto protocolType = getRHS();

auto getArgumentAt = [](const ApplyExpr *AE, unsigned index) -> Expr * {
assert(AE);

auto *arg = AE->getArg();
if (auto *TE = dyn_cast<TupleExpr>(arg))
return TE->getElement(index);

assert(index == 0);
if (auto *PE = dyn_cast<ParenExpr>(arg))
return PE->getSubExpr();

return arg;
};

// If this is a requirement of a pattern-matching operator,
// let's see whether argument is already has a fix associated
// let's see whether argument already has a fix associated
// with it and if so skip conformance error, otherwise we'd
// produce an unrelated `<type> doesn't conform to Equatable protocol`
// diagnostic.
Expand All @@ -588,43 +573,14 @@ bool MissingConformanceFailure::diagnoseAsError() {
if (diagnoseAsAmbiguousOperatorRef())
return true;

Optional<unsigned> atParameterPos;
// Sometimes fix is recorded by type-checking sub-expression
// during normal diagnostics, in such case call expression
// is unavailable.
if (Apply) {
if (auto *fnType = ownerType->getAs<AnyFunctionType>()) {
auto parameters = fnType->getParams();
for (auto index : indices(parameters)) {
if (parameters[index].getOldType()->isEqual(nonConformingType)) {
atParameterPos = index;
break;
}
}
}
}

if (nonConformingType->isObjCExistentialType()) {
emitDiagnostic(anchor->getLoc(), diag::protocol_does_not_conform_static,
nonConformingType, protocolType);
return true;
}

if (diagnoseTypeCannotConform((atParameterPos ?
getArgumentAt(Apply, *atParameterPos) : anchor),
nonConformingType, protocolType)) {
return true;
}

if (atParameterPos) {
// Requirement comes from one of the parameter types,
// let's try to point diagnostic to the argument expression.
auto *argExpr = getArgumentAt(Apply, *atParameterPos);
emitDiagnostic(argExpr->getLoc(),
diag::cannot_convert_argument_value_protocol,
nonConformingType, protocolType);
if (diagnoseTypeCannotConform(anchor, nonConformingType, protocolType))
return true;
}

// If none of the special cases could be diagnosed,
// let's fallback to the most general diagnostic.
Expand Down
9 changes: 6 additions & 3 deletions test/ClangImporter/newtype_conformance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import MoreSwiftNewtypes

func acceptEquatable<T: Equatable>(_: T) {}
func acceptHashable<T: Hashable>(_: T) {}
// expected-note@-1 {{where 'T' = 'WrappedRef'}}
// expected-note@-2 {{where 'T' = 'WrappedValue'}}
func acceptComparable<T: Comparable>(_: T) {}
// expected-note@-1 {{where 'T' = 'NSNotification.Name'}}

func testNewTypeWrapper(x: NSNotification.Name, y: NSNotification.Name) {
acceptEquatable(x)
acceptHashable(x)
acceptComparable(x) // expected-error {{does not conform to expected type 'Comparable'}}
acceptComparable(x) // expected-error {{global function 'acceptComparable' requires that 'NSNotification.Name' conform to 'Comparable'}}

_ = x == y
_ = x != y
Expand All @@ -30,6 +33,6 @@ func testNewTypeWrapper(x: NSNotification.Name, y: NSNotification.Name) {
func testCustomWrappers(wrappedRef: WrappedRef, wrappedValue: WrappedValue) {
acceptEquatable(wrappedRef)
acceptEquatable(wrappedValue)
acceptHashable(wrappedRef) // expected-error {{does not conform to expected type 'Hashable'}}
acceptHashable(wrappedValue) // expected-error {{does not conform to expected type 'Hashable'}}
acceptHashable(wrappedRef) // expected-error {{global function 'acceptHashable' requires that 'WrappedRef' conform to 'Hashable'}}
acceptHashable(wrappedValue) // expected-error {{global function 'acceptHashable' requires that 'WrappedValue' conform to 'Hashable'}}
}
11 changes: 6 additions & 5 deletions test/Constraints/diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func f5<T : P2>(_ : T) { }
// expected-note@-1 {{required by global function 'f5' where 'T' = '(Int) -> Int'}}
// expected-note@-2 {{required by global function 'f5' where 'T' = '(Int, String)'}}
// expected-note@-3 {{required by global function 'f5' where 'T' = 'Int.Type'}}
// expected-note@-4 {{where 'T' = 'Int'}}

func f6<T : P, U : P>(_ t: T, _ u: U) where T.SomeType == U.SomeType {}

Expand Down Expand Up @@ -75,10 +76,10 @@ i.wobble() // expected-error{{value of type 'Int' has no member 'wobble'}}

// Generic member does not conform.
extension Int {
func wibble<T: P2>(_ x: T, _ y: T) -> T { return x }
func wibble<T: P2>(_ x: T, _ y: T) -> T { return x } // expected-note {{where 'T' = 'Int'}}
func wubble<T>(_ x: (Int) -> T) -> T { return x(self) }
}
i.wibble(3, 4) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}}
i.wibble(3, 4) // expected-error {{instance method 'wibble' requires that 'Int' conform to 'P2'}}

// Generic member args correct, but return type doesn't match.
struct A : P2 {
Expand All @@ -98,9 +99,9 @@ func f7() -> (c: Int, v: A) {
return f6(g) // expected-error {{cannot convert return expression of type '(c: Int, i: A)' to return type '(c: Int, v: A)'}}
}

func f8<T:P2>(_ n: T, _ f: @escaping (T) -> T) {}
func f8<T:P2>(_ n: T, _ f: @escaping (T) -> T) {} // expected-note {{where 'T' = 'Int'}}
// expected-note@-1 {{required by global function 'f8' where 'T' = 'Tup' (aka '(Int, Double)')}}
f8(3, f4) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}}
f8(3, f4) // expected-error {{global function 'f8' requires that 'Int' conform to 'P2'}}
typealias Tup = (Int, Double)
func f9(_ x: Tup) -> Tup { return x }
f8((1,2.0), f9) // expected-error {{type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only struct/enum/class types can conform to protocols}}
Expand All @@ -111,7 +112,7 @@ f8((1,2.0), f9) // expected-error {{type 'Tup' (aka '(Int, Double)') cannot conf
"awfawf".doesntExist(0) // expected-error {{value of type 'String' has no member 'doesntExist'}}

// Does not conform to protocol.
f5(i) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}}
f5(i) // expected-error {{global function 'f5' requires that 'Int' conform to 'P2'}}

// Make sure we don't leave open existentials when diagnosing.
// <rdar://problem/20598568>
Expand Down
6 changes: 3 additions & 3 deletions test/Constraints/generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

infix operator +++

protocol ConcatToAnything {
protocol ConcatToAnything { // expected-note {{where 'Self' = 'U'}}
static func +++ <T>(lhs: Self, other: T)
}

Expand All @@ -14,7 +14,7 @@ func min<T : Comparable>(_ x: T, y: T) -> T {
func weirdConcat<T : ConcatToAnything, U>(_ t: T, u: U) {
t +++ u
t +++ 1
u +++ t // expected-error{{argument type 'U' does not conform to expected type 'ConcatToAnything'}}
u +++ t // expected-error{{referencing operator function '+++' on 'ConcatToAnything' requires that 'U' conform to 'ConcatToAnything'}}
}

// Make sure that the protocol operators don't get in the way.
Expand Down Expand Up @@ -647,7 +647,7 @@ struct BottleLayout {
}
let arr = [BottleLayout]()
let layout = BottleLayout(count:1)
let ix = arr.firstIndex(of:layout) // expected-error {{argument type 'BottleLayout' does not conform to expected type 'Equatable'}}
let ix = arr.firstIndex(of:layout) // expected-error {{referencing instance method 'firstIndex(of:)' on 'Collection' requires that 'BottleLayout' conform to 'Equatable'}}

let _: () -> UInt8 = { .init("a" as Unicode.Scalar) } // expected-error {{missing argument label 'ascii:' in call}}

Expand Down
7 changes: 7 additions & 0 deletions test/Constraints/protocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,10 @@ func rdar_50512161() {
foo(item: item) // expected-error {{generic parameter 'I' could not be inferred}}
}
}

// SR-11609: Compiler crash on missing conformance for default param
func test_sr_11609() {
func foo<T : Initable>(_ x: T = .init()) -> T { x } // expected-note {{where 'T' = 'String'}}
let _: String = foo()
// expected-error@-1 {{local function 'foo' requires that 'String' conform to 'Initable'}}
}
2 changes: 1 addition & 1 deletion test/Constraints/rdar40002266.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import Foundation
struct S {
init<T: NSNumber>(_ num: T) { // expected-note {{where 'T' = 'Bool'}}
self.init(num != 0) // expected-error {{initializer 'init(_:)' requires that 'Bool' inherit from 'NSNumber'}}
// expected-error@-1 {{argument type 'T' does not conform to expected type 'BinaryInteger'}}
// expected-error@-1 {{referencing operator function '!=' on 'BinaryInteger' requires that 'T' conform to 'BinaryInteger'}}
}
}
2 changes: 1 addition & 1 deletion test/Constraints/tuple.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ variadicWithTrailingClosure(fn: +)
func gcd_23700031<T>(_ a: T, b: T) {
var a = a
var b = b
(a, b) = (b, a % b) // expected-error {{argument type 'T' does not conform to expected type 'BinaryInteger'}}
(a, b) = (b, a % b) // expected-error {{protocol 'BinaryInteger' requires that 'T' conform to 'BinaryInteger'}}
}

// <rdar://problem/24210190>
Expand Down
10 changes: 5 additions & 5 deletions test/Generics/deduction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ protocol IsBefore {
func isBefore(_ other: Self) -> Bool
}

func min2<T : IsBefore>(_ x: T, _ y: T) -> T {
func min2<T : IsBefore>(_ x: T, _ y: T) -> T { // expected-note {{where 'T' = 'Float'}}
if y.isBefore(x) { return y }
return x
}
Expand All @@ -205,7 +205,7 @@ extension Int : IsBefore {

func callMin(_ x: Int, y: Int, a: Float, b: Float) {
_ = min2(x, y)
min2(a, b) // expected-error{{argument type 'Float' does not conform to expected type 'IsBefore'}}
min2(a, b) // expected-error{{global function 'min2' requires that 'Float' conform to 'IsBefore'}}
}

func rangeOfIsBefore<R : IteratorProtocol>(_ range: R) where R.Element : IsBefore {} // expected-note {{where 'R.Element' = 'IndexingIterator<[Double]>.Element' (aka 'Double')}}
Expand Down Expand Up @@ -241,11 +241,11 @@ genericInheritsA(C_GI())
//===----------------------------------------------------------------------===//
// Deduction for member operators
//===----------------------------------------------------------------------===//
protocol Addable {
protocol Addable { // expected-note {{where 'Self' = 'U'}}
static func +(x: Self, y: Self) -> Self
}
func addAddables<T : Addable, U>(_ x: T, y: T, u: U) -> T {
u + u // expected-error{{argument type 'U' does not conform to expected type 'Addable'}}
u + u // expected-error{{protocol 'Addable' requires that 'U' conform to 'Addable'}}
return x+y
}

Expand Down Expand Up @@ -314,7 +314,7 @@ func foo() {
for i in min(1,2) { // expected-error{{type 'Int' does not conform to protocol 'Sequence'}}
}
let j = min(Int(3), Float(2.5)) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}}
let k = min(A(), A()) // expected-error{{argument type 'A' does not conform to expected type 'Comparable'}}
let k = min(A(), A()) // expected-error{{global function 'min' requires that 'A' conform to 'Comparable'}}
let oi : Int? = 5
let l = min(3, oi) // expected-error{{value of optional type 'Int?' must be unwrapped}}
// expected-note@-1{{coalesce}}
Expand Down
4 changes: 2 additions & 2 deletions test/Generics/unbound.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ class SomeClassWithInvalidMethod {
// <rdar://problem/20792596> QoI: Cannot invoke with argument list (T), expected an argument list of (T)
protocol r20792596P {}

func foor20792596<T: r20792596P>(x: T) -> T {
func foor20792596<T: r20792596P>(x: T) -> T { // expected-note {{where 'T' = 'T'}}
return x
}

func callfoor20792596<T>(x: T) -> T {
return foor20792596(x)
// expected-error@-1 {{missing argument label 'x:' in call}}
// expected-error@-2 {{argument type 'T' does not conform to expected type 'r20792596P'}}
// expected-error@-2 {{global function 'foor20792596(x:)' requires that 'T' conform to 'r20792596P'}}
}

// <rdar://problem/31181895> parameter "not used in function signature" when part of a superclass constraint
Expand Down
4 changes: 2 additions & 2 deletions test/Sema/diag_ambiguous_overloads.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ _ = sr7918_Suit.foo(&myRNG) // expected-error {{cannot pass immutable value as i
//=-------------- SR-7786 --------------=/
struct sr7786 {
func foo() -> UInt { return 0 }
func foo<T: UnsignedInteger>(bar: T) -> T {
func foo<T: UnsignedInteger>(bar: T) -> T { // expected-note {{where 'T' = 'Int'}}
return bar
}
}

let s = sr7786()
let a = s.foo()
let b = s.foo(bar: 123) // expected-error {{argument type 'Int' does not conform to expected type 'UnsignedInteger'}}
let b = s.foo(bar: 123) // expected-error {{instance method 'foo(bar:)' requires that 'Int' conform to 'UnsignedInteger'}}
let c: UInt = s.foo(bar: 123)
let d = s.foo(bar: 123 as UInt)

Expand Down
2 changes: 1 addition & 1 deletion test/attr/attr_dynamic_member_lookup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ func keypath_with_incorrect_return_type(_ arr: Lens<Array<Int>>) {
// expected-error@-1 {{operator function '..<' requires that 'Lens<Int>' conform to 'Strideable'}}
// expected-error@-2 {{operator function '..<' requires that 'Lens<Int>.Stride' conform to 'SignedInteger'}}
// expected-error@-3 {{cannot convert value of type 'Int' to expected argument type 'Lens<Int>'}}
// expected-error@-4 {{argument type 'Lens<Int>' does not conform to expected type 'Comparable'}}
// expected-error@-4 {{referencing operator function '..<' on 'Comparable' requires that 'Lens<Int>' conform to 'Comparable'}}
let _ = arr[idx]
}
}
Expand Down
4 changes: 2 additions & 2 deletions test/decl/enum/objc_enum_Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import Foundation

func acceptBridgeableNSError<E : _ObjectiveCBridgeableError>(_ e: E) { }
func acceptBridgeableNSError<E : _ObjectiveCBridgeableError>(_ e: E) { } // expected-note {{where 'E' = 'E3'}}

@objc enum E2 : Int, Error {
case A = 1
Expand All @@ -18,4 +18,4 @@ acceptBridgeableNSError(E2.A)
}

acceptBridgeableNSError(E3.A)
// expected-error@-1{{argument type 'E3' does not conform to expected type '_ObjectiveCBridgeableError'}}
// expected-error@-1{{global function 'acceptBridgeableNSError' requires that 'E3' conform to '_ObjectiveCBridgeableError'}}
4 changes: 2 additions & 2 deletions test/decl/ext/generic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func intArray(_ x: [Int]) {

class GenericClass<T> { }

extension GenericClass where T : Equatable {
extension GenericClass where T : Equatable { // expected-note {{where 'T' = 'T'}}
func foo(_ x: T, y: T) -> Bool { return x == y }
}

Expand All @@ -140,7 +140,7 @@ func genericClassEquatable<T : Equatable>(_ gc: GenericClass<T>, x: T, y: T) {
}

func genericClassNotEquatable<T>(_ gc: GenericClass<T>, x: T, y: T) {
gc.foo(x, y: y) // expected-error{{argument type 'T' does not conform to expected type 'Equatable'}}
gc.foo(x, y: y) // expected-error{{referencing instance method 'foo(_:y:)' on 'GenericClass' requires that 'T' conform to 'Equatable'}}
}


Expand Down
2 changes: 1 addition & 1 deletion test/expr/expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ func testNilCoalescePrecedence(cond: Bool, a: Int?, r: ClosedRange<Int>?) {
// ?? should have lower precedence than range and arithmetic operators.
let r1 = r ?? (0...42) // ok
let r2 = (r ?? 0)...42 // not ok: expected-error 2 {{cannot convert value of type 'Int' to expected argument type 'ClosedRange<Int>'}}
// expected-error@-1 {{argument type 'ClosedRange<Int>' does not conform to expected type 'Comparable'}}
// expected-error@-1 {{referencing operator function '...' on 'Comparable' requires that 'ClosedRange<Int>' conform to 'Comparable'}}
let r3 = r ?? 0...42 // parses as the first one, not the second.


Expand Down
4 changes: 2 additions & 2 deletions test/expr/unary/keypath/salvage-with-other-type-errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct S {

protocol K { }

func + <Object>(lhs: KeyPath<A, Object>, rhs: String) -> P<Object> {
func + <Object>(lhs: KeyPath<A, Object>, rhs: String) -> P<Object> { // expected-note {{where 'Object' = 'String'}}
fatalError()
}

Expand All @@ -27,7 +27,7 @@ struct A {
}

extension A: K {
static let j = S(\A.id + "id") // expected-error {{argument type 'String' does not conform to expected type 'K'}}
static let j = S(\A.id + "id") // expected-error {{operator function '+' requires that 'String' conform to 'K'}}
}

// SR-5034
Expand Down
12 changes: 8 additions & 4 deletions test/stdlib/StringDiagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,23 +63,27 @@ func testStringDeprecation(hello: String) {
func acceptsCollection<C: Collection>(_: C) {}
func acceptsBidirectionalCollection<C: BidirectionalCollection>(_: C) {}
func acceptsRandomAccessCollection<C: RandomAccessCollection>(_: C) {}
// expected-note@-1 {{where 'C' = 'String.UTF8View'}}
// expected-note@-2 {{where 'C' = 'String.UnicodeScalarView'}}
// expected-note@-3 {{where 'C' = 'String.UTF16View'}}
// expected-note@-4 {{where 'C' = 'String'}}

func testStringCollectionTypes(s: String) {
acceptsCollection(s.utf8)
acceptsBidirectionalCollection(s.utf8)
acceptsRandomAccessCollection(s.utf8) // expected-error{{argument type 'String.UTF8View' does not conform to expected type 'RandomAccessCollection'}}
acceptsRandomAccessCollection(s.utf8) // expected-error{{global function 'acceptsRandomAccessCollection' requires that 'String.UTF8View' conform to 'RandomAccessCollection'}}

acceptsCollection(s.utf16)
acceptsBidirectionalCollection(s.utf16)
acceptsRandomAccessCollection(s.utf16) // expected-error{{argument type 'String.UTF16View' does not conform to expected type 'RandomAccessCollection'}}
acceptsRandomAccessCollection(s.utf16) // expected-error{{global function 'acceptsRandomAccessCollection' requires that 'String.UTF16View' conform to 'RandomAccessCollection'}}

acceptsCollection(s.unicodeScalars)
acceptsBidirectionalCollection(s.unicodeScalars)
acceptsRandomAccessCollection(s.unicodeScalars) // expected-error{{argument type 'String.UnicodeScalarView' does not conform to expected type 'RandomAccessCollection'}}
acceptsRandomAccessCollection(s.unicodeScalars) // expected-error{{global function 'acceptsRandomAccessCollection' requires that 'String.UnicodeScalarView' conform to 'RandomAccessCollection'}}

acceptsCollection(s)
acceptsBidirectionalCollection(s)
acceptsRandomAccessCollection(s) // expected-error{{argument type 'String' does not conform to expected type 'RandomAccessCollection'}}
acceptsRandomAccessCollection(s) // expected-error{{global function 'acceptsRandomAccessCollection' requires that 'String' conform to 'RandomAccessCollection'}}
}

// In previous versions of Swift, code would accidentally select
Expand Down
Loading