diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 016697ec13515..b74e3c6c67a8c 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -30,14 +30,17 @@ void ConstraintSystem::inferTransitiveSupertypeBindings( llvm::SmallVector subtypeOf; // First, let's collect all of the `subtype` constraints associated // with this type variable. - llvm::copy_if(bindings.Sources, std::back_inserter(subtypeOf), - [&](const Constraint *constraint) -> bool { - if (constraint->getKind() != ConstraintKind::Subtype) - return false; - - auto rhs = simplifyType(constraint->getSecondType()); - return rhs->getAs() == typeVar; - }); + llvm::copy_if( + bindings.Sources, std::back_inserter(subtypeOf), + [&](const Constraint *constraint) -> bool { + if (constraint->getKind() != ConstraintKind::Subtype && + constraint->getKind() != ConstraintKind::ArgumentConversion && + constraint->getKind() != ConstraintKind::OperatorArgumentConversion) + return false; + + auto rhs = simplifyType(constraint->getSecondType()); + return rhs->getAs() == typeVar; + }); if (subtypeOf.empty()) return; @@ -618,7 +621,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { continue; literalBindings.push_back( - {defaultType, AllowedBindingKind::Subtypes, constraint}); + {defaultType, AllowedBindingKind::Exact, constraint}); continue; } @@ -644,7 +647,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { if (!matched) { exactTypes.insert(defaultType->getCanonicalType()); literalBindings.push_back( - {defaultType, AllowedBindingKind::Subtypes, constraint}); + {defaultType, AllowedBindingKind::Exact, constraint}); } break; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 1125887e8ddc4..64d11e263c807 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -9103,7 +9103,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( // subscript, which requires changes to declaration to become mutable. if (auto last = locator.last()) { impact += (last->is() || - last->is()) + last->is() || + last->is()) ? 1 : 0; } diff --git a/lib/Sema/CSStep.h b/lib/Sema/CSStep.h index 221e2a0c01396..8e948c73afe52 100644 --- a/lib/Sema/CSStep.h +++ b/lib/Sema/CSStep.h @@ -620,6 +620,15 @@ class TypeVariableStep final : public BindingStep { /// Check whether attempting type variable binding choices should /// be stopped, because optimal solution has already been found. bool shouldStopAt(const TypeVariableBinding &choice) const override { + if (CS.shouldAttemptFixes()) { + // Let's always attempt default types inferred from literals + // in diagnostic mode because that could lead to better + // diagnostics if the problem is contextual like argument/parameter + // conversion or collection element mismatch. + if (choice.hasDefaultedProtocol()) + return false; + } + // If we were able to solve this without considering // default literals, don't bother looking at default literals. return AnySolved && choice.hasDefaultedProtocol() && diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 27540274176a7..9cefb28170975 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2778,45 +2778,61 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs, auto &DE = cs.getASTContext().Diags; - llvm::SmallDenseMap> conflicts; + llvm::SmallDenseMap, 4> + genericParams; + // Consider only representative type variables shared across + // all of the solutions. + for (auto *typeVar : cs.getTypeVariables()) { + if (auto *GP = typeVar->getImpl().getGenericParameter()) { + auto *locator = typeVar->getImpl().getLocator(); + auto *repr = cs.getRepresentative(typeVar); + // If representative is another generic parameter let's + // use its generic parameter type instead of originator's, + // but it's possible that generic parameter is equated to + // some other type e.g. + // + // func foo(_: T) -> T {} + // + // In this case when reference to function `foo` is "opened" + // type variable representing `T` would be equated to + // type variable representing a result type of the reference. + if (auto *reprGP = repr->getImpl().getGenericParameter()) + GP = reprGP; + + genericParams[repr] = {GP, locator->getAnchor()->getLoc()}; + } + } - for (const auto &binding : solutions[0].typeBindings) { - auto *typeVar = binding.first; + llvm::SmallDenseMap, + SmallVector> + conflicts; - if (!typeVar->getImpl().getGenericParameter()) - continue; + for (const auto &entry : genericParams) { + auto *typeVar = entry.first; + auto GP = entry.second; llvm::SmallSetVector arguments; - arguments.insert(binding.second); - - if (!llvm::all_of(solutions.slice(1), [&](const Solution &solution) { - auto binding = solution.typeBindings.find(typeVar); - if (binding == solution.typeBindings.end()) - return false; - - // Contextual opaque result type is uniquely identified by - // declaration it's associated with, so we have to compare - // declarations instead of using pointer equality on such types. - if (auto *opaque = - binding->second->getAs()) { - auto *decl = opaque->getDecl(); - arguments.remove_if([&](Type argType) -> bool { - if (auto *otherOpaque = - argType->getAs()) { - return decl == otherOpaque->getDecl(); - } - return false; - }); + for (const auto &solution : solutions) { + auto type = solution.typeBindings.lookup(typeVar); + // Contextual opaque result type is uniquely identified by + // declaration it's associated with, so we have to compare + // declarations instead of using pointer equality on such types. + if (auto *opaque = type->getAs()) { + auto *decl = opaque->getDecl(); + arguments.remove_if([&](Type argType) -> bool { + if (auto *otherOpaque = argType->getAs()) { + return decl == otherOpaque->getDecl(); } + return false; + }); + } - arguments.insert(binding->second); - return true; - })) - continue; - - if (arguments.size() > 1) { - conflicts[typeVar].append(arguments.begin(), arguments.end()); + arguments.insert(type); } + + if (arguments.size() > 1) + conflicts[GP].append(arguments.begin(), arguments.end()); } auto getGenericTypeDecl = [&](ArchetypeType *archetype) -> ValueDecl * { @@ -2833,8 +2849,10 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs, bool diagnosed = false; for (auto &conflict : conflicts) { - auto *typeVar = conflict.first; - auto *locator = typeVar->getImpl().getLocator(); + SourceLoc loc; + GenericTypeParamType *GP; + + std::tie(GP, loc) = conflict.first; auto conflictingArguments = conflict.second; llvm::SmallString<64> arguments; @@ -2859,10 +2877,8 @@ static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs, }, [&OS] { OS << " vs. "; }); - auto *anchor = locator->getAnchor(); - DE.diagnose(anchor->getLoc(), - diag::conflicting_arguments_for_generic_parameter, - typeVar->getImpl().getGenericParameter(), OS.str()); + DE.diagnose(loc, diag::conflicting_arguments_for_generic_parameter, GP, + OS.str()); diagnosed = true; } diff --git a/test/Constraints/array_literal.swift b/test/Constraints/array_literal.swift index 0ac54dd53550b..73e772791ab15 100644 --- a/test/Constraints/array_literal.swift +++ b/test/Constraints/array_literal.swift @@ -50,7 +50,7 @@ useDoubleList([1.0,2,3]) useDoubleList([1.0,2.0,3.0]) useIntDict(["Niners" => 31, "Ravens" => 34]) -useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type 'Double' to expected argument type 'Int'}} +useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type 'Double' to expected element type 'Int'}} // QoI: Propagate contextual information in a call to operands useDoubleDict(["Niners" => 31, "Ravens" => 34.0]) useDoubleDict(["Niners" => 31.0, "Ravens" => 34]) diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index 0c7de172b93b0..3a5841fd1310f 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -456,13 +456,7 @@ extension Collection { } } func fn_r28909024(n: Int) { - // FIXME(diagnostics): Unfortunately there is no easy way to fix this diagnostic issue at the moment - // because the problem is related to ordering of the bindings - we'd attempt to bind result of the expression - // to contextual type of `Void` which prevents solver from discovering correct types for range - 0..<10 - // (since both arguments are literal they are ranked lower than contextual type). - // - // Good diagnostic for this is - `unexpected non-void return value in void function` - return (0..<10).r28909024 { // expected-error {{type of expression is ambiguous without more context}} + return (0..<10).r28909024 { // expected-error {{unexpected non-void return value in void function}} expected-note {{did you mean to add a return type?}} _ in true } } diff --git a/test/Constraints/default_literals.swift b/test/Constraints/default_literals.swift index f52e85ec2ac62..02f79b446f64d 100644 --- a/test/Constraints/default_literals.swift +++ b/test/Constraints/default_literals.swift @@ -42,3 +42,14 @@ extension Int { var (div, mod) = (9 / 4, 9 % 4) + +// rdar://problem/56212087 - solver fails to infer correct type for a generic parameter (Any vs. String) +func test_transitive_inference_of_default_literal_types() { + func foo(_: String, _: T) -> T { + fatalError() + } + + func bar(_: Any?) {} + + bar(foo("", "")) // Ok +} diff --git a/test/Generics/deduction.swift b/test/Generics/deduction.swift index a06278ca67b8a..d8d3e14fc07bd 100644 --- a/test/Generics/deduction.swift +++ b/test/Generics/deduction.swift @@ -318,8 +318,9 @@ func foo() { let j = min(Int(3), Float(2.5)) // expected-error{{conflicting arguments to generic parameter 'T' ('Int' vs. 'Float')}} 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{{global function 'min' requires that 'Int?' conform to 'Comparable'}} - // expected-note@-1{{wrapped type 'Int' satisfies this requirement}} + let l = min(3, oi) // expected-error{{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}} + // expected-note@-1 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} + // expected-note@-2 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} } infix operator +& diff --git a/test/Parse/omit_return.swift b/test/Parse/omit_return.swift index 6a1a3b39f4386..07544df94e8da 100644 --- a/test/Parse/omit_return.swift +++ b/test/Parse/omit_return.swift @@ -1005,7 +1005,7 @@ var fvs_stubMyOwnFatalError: () { var fvs_forceTryExplicit: String { get { "ok" } set { - return try! failableIdentity("shucks") // expected-error {{cannot convert value of type 'String' to expected argument type '()'}} + return try! failableIdentity("shucks") // expected-error {{unexpected non-void return value in void function}} } } diff --git a/test/attr/attr_dynamic_member_lookup.swift b/test/attr/attr_dynamic_member_lookup.swift index 357ea7f0af9e0..a98e650d44d0b 100644 --- a/test/attr/attr_dynamic_member_lookup.swift +++ b/test/attr/attr_dynamic_member_lookup.swift @@ -600,10 +600,7 @@ func keypath_with_subscripts(_ arr: SubscriptLens<[Int]>, func keypath_with_incorrect_return_type(_ arr: Lens>) { for idx in 0..' conform to 'Strideable'}} - // expected-error@-2 {{protocol 'Sequence' requires that 'Lens.Stride' conform to 'SignedInteger'}} - // expected-error@-3 {{cannot convert value of type 'Int' to expected argument type 'Lens'}} - // expected-error@-4 {{referencing operator function '..<' on 'Comparable' requires that 'Lens' conform to 'Comparable'}} + // expected-error@-1 {{cannot convert value of type 'Lens' to expected argument type 'Int'}} let _ = arr[idx] } } diff --git a/test/decl/typealias/generic.swift b/test/decl/typealias/generic.swift index 27a6c4f4790b5..3d6678db37bb8 100644 --- a/test/decl/typealias/generic.swift +++ b/test/decl/typealias/generic.swift @@ -103,7 +103,7 @@ _ = A(a: "foo", // expected-error {{cannot convert value of type 'S b: 42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}} _ = B(a: 12, b: 42) _ = B(a: 12, b: 42 as Float) -_ = B(a: "foo", b: 42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}} +_ = B(a: "foo", b: 42) // expected-error {{conflicting arguments to generic parameter 'T1' ('String' vs. 'Int')}} _ = C(a: "foo", b: 42) _ = C(a: 42, // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}} b: 42) diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index d7d8f7126cc16..95b23de79e9b6 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -791,8 +791,9 @@ func testNilCoalescePrecedence(cond: Bool, a: Int?, r: ClosedRange?) { // ?? 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'}} - // expected-error@-1 {{referencing operator function '...' on 'Comparable' requires that 'ClosedRange' conform to 'Comparable'}} + let r2 = (r ?? 0)...42 // not ok + // expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'ClosedRange'}} + // expected-error@-2 {{cannot convert value of type 'ClosedRange' to expected argument type 'Int'}} let r3 = r ?? 0...42 // parses as the first one, not the second. diff --git a/test/type/protocol_composition.swift b/test/type/protocol_composition.swift index b78a9af3a5fd0..602cb721a11ae 100644 --- a/test/type/protocol_composition.swift +++ b/test/type/protocol_composition.swift @@ -173,7 +173,7 @@ takesP1AndP2([Swift.AnyObject & P1 & P2]()) takesP1AndP2([AnyObject & protocol_composition.P1 & P2]()) takesP1AndP2([AnyObject & P1 & protocol_composition.P2]()) takesP1AndP2([DoesNotExist & P1 & P2]()) // expected-error {{use of unresolved identifier 'DoesNotExist'}} -takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}} +takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}} expected-error {{cannot call value of non-function type 'Array<_>'}} typealias T08 = P1 & inout P2 // expected-error {{'inout' may only be used on parameters}} typealias T09 = P1 & __shared P2 // expected-error {{'__shared' may only be used on parameters}} diff --git a/validation-test/stdlib/FixedPointDiagnostics.swift.gyb b/validation-test/stdlib/FixedPointDiagnostics.swift.gyb index e091805af22b7..d025940e14c65 100644 --- a/validation-test/stdlib/FixedPointDiagnostics.swift.gyb +++ b/validation-test/stdlib/FixedPointDiagnostics.swift.gyb @@ -3,13 +3,13 @@ // RUN: %line-directive %t/main.swift -- %target-swift-frontend -typecheck -verify -swift-version 4.2 %t/main.swift func testUnaryMinusInUnsigned() { - var a: UInt8 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt8'}} expected-note * {{}} expected-warning * {{}} + var a: UInt8 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt8'}} expected-note * {{}} expected-warning * {{}} - var b: UInt16 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt16'}} expected-note * {{}} expected-warning * {{}} + var b: UInt16 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt16'}} expected-note * {{}} expected-warning * {{}} - var c: UInt32 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt32'}} expected-note * {{}} expected-warning * {{}} + var c: UInt32 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt32'}} expected-note * {{}} expected-warning * {{}} - var d: UInt64 = -(1) // expected-error {{no '-' candidates produce the expected contextual result type 'UInt64'}} expected-note * {{}} expected-warning * {{}} + var d: UInt64 = -(1) // expected-error {{cannot convert value of type 'Int' to specified type 'UInt64'}} expected-note * {{}} expected-warning * {{}} } // Int and UInt are not identical to any fixed-size integer type