[CSBindings] Open collection before binding parameter only if original argument type failed

Instead of always opening argument type represented by a collection
without type variables (to support subtyping when element is a labeled tuple),
let's try original type first and if that fails use a slower path with
indirection which attempts `array upcast`. Doing it this way helps to
propagate contextual information faster which fixes a performance regression.

Resolves: rdar://problem/54580247
This commit is contained in:
Pavel Yaskevich
2020-02-27 15:04:43 -08:00
parent 0fb4ea1ec3
commit 20fc51d4f4
4 changed files with 25 additions and 21 deletions

View File

@@ -1043,6 +1043,25 @@ bool TypeVarBindingProducer::computeNext() {
if (auto simplifiedSuper = CS.checkTypeOfBinding(TypeVar, supertype)) if (auto simplifiedSuper = CS.checkTypeOfBinding(TypeVar, supertype))
addNewBinding(binding.withType(*simplifiedSuper)); addNewBinding(binding.withType(*simplifiedSuper));
} }
auto srcLocator = binding.getLocator();
if (srcLocator &&
srcLocator->isLastElement<LocatorPathElt::ApplyArgToParam>() &&
!type->hasTypeVariable() && CS.isCollectionType(type)) {
// If the type binding comes from the argument conversion, let's
// instead of binding collection types directly, try to bind
// using temporary type variables substituted for element
// types, that's going to ensure that subtype relationship is
// always preserved.
auto *BGT = type->castTo<BoundGenericType>();
auto UGT = UnboundGenericType::get(BGT->getDecl(), BGT->getParent(),
BGT->getASTContext());
auto dstLocator = TypeVar->getImpl().getLocator();
auto newType = CS.openUnboundGenericType(UGT, dstLocator)
->reconstituteSugar(/*recursive=*/false);
addNewBinding(binding.withType(newType));
}
} }
if (newBindings.empty()) if (newBindings.empty())
@@ -1062,20 +1081,6 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
if (Binding.hasDefaultedLiteralProtocol()) { if (Binding.hasDefaultedLiteralProtocol()) {
type = cs.openUnboundGenericType(type, dstLocator); type = cs.openUnboundGenericType(type, dstLocator);
type = type->reconstituteSugar(/*recursive=*/false); type = type->reconstituteSugar(/*recursive=*/false);
} else if (srcLocator &&
srcLocator->isLastElement<LocatorPathElt::ApplyArgToParam>() &&
!type->hasTypeVariable() && cs.isCollectionType(type)) {
// If the type binding comes from the argument conversion, let's
// instead of binding collection types directly, try to bind
// using temporary type variables substituted for element
// types, that's going to ensure that subtype relationship is
// always preserved.
auto *BGT = type->castTo<BoundGenericType>();
auto UGT = UnboundGenericType::get(BGT->getDecl(), BGT->getParent(),
BGT->getASTContext());
type = cs.openUnboundGenericType(UGT, dstLocator);
type = type->reconstituteSugar(/*recursive=*/false);
} }
cs.addConstraint(ConstraintKind::Bind, TypeVar, type, srcLocator); cs.addConstraint(ConstraintKind::Bind, TypeVar, type, srcLocator);

View File

@@ -3799,9 +3799,11 @@ bool ConstraintSystem::repairFailures(
if (tupleLocator->isLastElement<LocatorPathElt::SequenceElementType>()) if (tupleLocator->isLastElement<LocatorPathElt::SequenceElementType>())
break; break;
// Generic argument failures have a more general fix which is attached to a // Generic argument/requirement failures have a more general fix which
// parent type and aggregates all argument failures into a single fix. // is attached to a parent type and aggregates all argument failures
if (tupleLocator->isLastElement<LocatorPathElt::GenericArgument>()) // into a single fix.
if (tupleLocator->isLastElement<LocatorPathElt::AnyRequirement>() ||
tupleLocator->isLastElement<LocatorPathElt::GenericArgument>())
break; break;
ConstraintFix *fix; ConstraintFix *fix;

View File

@@ -216,7 +216,6 @@ func rdar_50668864() {
struct Foo { struct Foo {
init(anchors: [Int]) { // expected-note {{'init(anchors:)' declared here}} init(anchors: [Int]) { // expected-note {{'init(anchors:)' declared here}}
self = .init { _ in [] } // expected-error {{trailing closure passed to parameter of type '[Int]' that does not accept a closure}} self = .init { _ in [] } // expected-error {{trailing closure passed to parameter of type '[Int]' that does not accept a closure}}
// expected-error@-1 {{generic parameter 'Element' could not be inferred}}
} }
} }
} }

View File

@@ -1,7 +1,5 @@
// FIXME: This should be linear instead of exponential. // RUN: %scale-test --begin 1 --end 20 --step 1 --select NumLeafScopes %s -Xfrontend=-solver-expression-time-threshold=1
// RUN: %scale-test --begin 1 --end 10 --step 1 --select NumLeafScopes --invert-result %s -Xfrontend=-solver-expression-time-threshold=1
// REQUIRES: asserts,no_asan // REQUIRES: asserts,no_asan
// REQUIRES: rdar57138194,SR11770
enum Val { enum Val {
case d([String: Val]) case d([String: Val])