Skip to content

Commit 0da0d10

Browse files
authored
Merge pull request #15419 from rudkx/faster-typecheck-tuples
Fix exponential type checking of tuple literals.
2 parents 536c232 + 9385dbb commit 0da0d10

File tree

8 files changed

+59
-32
lines changed

8 files changed

+59
-32
lines changed

lib/Sema/CSGen.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,40 +1984,52 @@ namespace {
19841984
// Var doesn't affect the type.
19851985
return getTypeForPattern(cast<VarPattern>(pattern)->getSubPattern(),
19861986
locator);
1987-
case PatternKind::Any:
1988-
// For a pattern of unknown type, create a new type variable.
1987+
case PatternKind::Any: {
1988+
// If we have a type from an initializer expression, and that
1989+
// expression does not produce an InOut type, use it. This
1990+
// will avoid exponential typecheck behavior in the case of
1991+
// tuples, nested arrays, and dictionary literals.
1992+
//
1993+
// Otherwise, create a new type variable.
1994+
auto boundExpr = locator.trySimplifyToExpr();
1995+
1996+
if (boundExpr) {
1997+
auto boundExprTy = CS.getType(boundExpr);
1998+
if (!boundExprTy->is<InOutType>())
1999+
return boundExprTy->getRValueType();
2000+
}
2001+
19892002
return CS.createTypeVariable(CS.getConstraintLocator(locator),
19902003
TVO_CanBindToInOut);
2004+
}
19912005

19922006
case PatternKind::Named: {
19932007
auto var = cast<NamedPattern>(pattern)->getDecl();
1994-
2008+
auto isWeak = false;
2009+
if (auto *OA = var->getAttrs().getAttribute<ReferenceOwnershipAttr>())
2010+
isWeak = OA->get() == ReferenceOwnership::Weak;
2011+
19952012
auto boundExpr = locator.trySimplifyToExpr();
1996-
auto haveBoundCollectionLiteral = boundExpr &&
1997-
!var->hasNonPatternBindingInit() &&
1998-
(isa<ArrayExpr>(boundExpr) ||
1999-
isa<DictionaryExpr>(boundExpr));
2013+
auto haveBoundExpr = boundExpr && !var->hasNonPatternBindingInit();
20002014

2001-
// For a named pattern without a type, create a new type variable
2002-
// and use it as the type of the variable.
2015+
// If we have a type from an initializer expression, and that
2016+
// expression does not produce an InOut type, use it. This
2017+
// will avoid exponential typecheck behavior in the case of
2018+
// tuples, nested arrays, and dictionary literals.
20032019
//
2004-
// FIXME: For now, substitute in the bound type for literal collection
2005-
// exprs that would otherwise result in a simple conversion constraint
2006-
// being placed between two type variables. (The bound type and the
2007-
// collection type, which will always be the same in this case.)
2008-
// This will avoid exponential typecheck behavior in the case of nested
2009-
// array and dictionary literals.
2010-
Type ty = haveBoundCollectionLiteral ?
2011-
CS.getType(boundExpr) :
2012-
CS.createTypeVariable(CS.getConstraintLocator(locator),
2013-
TVO_CanBindToInOut);
2020+
// Otherwise, create a new type variable.
2021+
if (!isWeak && haveBoundExpr) {
2022+
auto boundExprTy = CS.getType(boundExpr);
2023+
if (!boundExprTy->is<InOutType>())
2024+
return boundExprTy->getRValueType();
2025+
}
2026+
2027+
Type ty = CS.createTypeVariable(CS.getConstraintLocator(locator),
2028+
TVO_CanBindToInOut);
20142029

20152030
// For weak variables, use Optional<T>.
2016-
if (auto *OA = var->getAttrs().getAttribute<ReferenceOwnershipAttr>())
2017-
if (OA->get() == ReferenceOwnership::Weak) {
2018-
ty = CS.getTypeChecker().getOptionalType(var->getLoc(), ty);
2019-
if (!ty) return Type();
2020-
}
2031+
if (isWeak)
2032+
return CS.getTypeChecker().getOptionalType(var->getLoc(), ty);
20212033

20222034
return ty;
20232035
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2131,7 +2131,9 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
21312131

21322132
Expr *foundSolution(Solution &solution, Expr *expr) override {
21332133
// Figure out what type the constraints decided on.
2134-
InitTypeAndInOut.setPointer(solution.simplifyType(InitTypeAndInOut.getPointer()));
2134+
auto ty = solution.simplifyType(InitTypeAndInOut.getPointer());
2135+
InitTypeAndInOut.setPointer(
2136+
ty->getRValueType()->reconstituteSugar(/*recursive =*/false));
21352137
InitTypeAndInOut.setInt(expr->isSemanticallyInOutExpr());
21362138

21372139
// Just keep going.

test/APINotes/versioned.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ func testAKA(structValue: ImportantCStruct, aliasValue: ImportantCAlias) {
118118

119119
let optStructValue: Optional = structValue
120120
let _: Int = optStructValue
121-
// CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:16: error: cannot convert value of type 'Optional<ImportantCStruct>' to specified type 'Int'
121+
// CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:16: error: cannot convert value of type 'ImportantCStruct?' to specified type 'Int'
122122

123123
let optAliasValue: Optional = aliasValue
124124
let _: Int = optAliasValue
125-
// CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:16: error: cannot convert value of type 'Optional<ImportantCAlias>' (aka 'Optional<Int32>') to specified type 'Int'
125+
// CHECK-DIAGS-3: versioned.swift:[[@LINE-1]]:16: error: cannot convert value of type 'ImportantCAlias?' (aka 'Optional<Int32>') to specified type 'Int'
126126
}
127127

128128
func testRenamedEnumConstants() {

test/Constraints/array_literal.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,15 @@ func defaultToAny(i: Int, s: String) {
129129

130130
let a2: Array = [1, "a", 3.5]
131131
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
132-
let _: Int = a2 // expected-error{{value of type 'Array<Any>'}}
132+
let _: Int = a2 // expected-error{{value of type '[Any]'}}
133133

134134
let a3 = [1, "a", nil, 3.5]
135135
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
136136
let _: Int = a3 // expected-error{{value of type '[Any?]'}}
137137

138138
let a4: Array = [1, "a", nil, 3.5]
139139
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
140-
let _: Int = a4 // expected-error{{value of type 'Array<Any?>'}}
140+
let _: Int = a4 // expected-error{{value of type '[Any?]'}}
141141

142142
let a5 = []
143143
// expected-error@-1{{empty collection literal requires an explicit type}}

test/Constraints/bridging.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ func rdar20029786(_ ns: NSString?) {
302302

303303
// <rdar://problem/19813772> QoI: Using as! instead of as in this case produces really bad diagnostic
304304
func rdar19813772(_ nsma: NSMutableArray) {
305-
var a1 = nsma as! Array // expected-error{{generic parameter 'Element' could not be inferred in cast to 'Array<_>'}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{26-26=<Any>}}
305+
var a1 = nsma as! Array // expected-error{{generic parameter 'Element' could not be inferred in cast to 'Array'}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{26-26=<Any>}}
306306
var a2 = nsma as! Array<AnyObject> // expected-warning{{forced cast from 'NSMutableArray' to 'Array<AnyObject>' always succeeds; did you mean to use 'as'?}} {{17-20=as}}
307307
var a3 = nsma as Array<AnyObject>
308308
}

test/Constraints/patterns.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,16 @@ func testOne() {
351351
if case One.E.SomeError = error {} // expected-error{{generic enum type 'One.E' is ambiguous without explicit generic parameters when matching value of type 'Error'}}
352352
}
353353
}
354+
355+
func overload(_ x: Int) -> Int { return x }
356+
func overload(_ x: Float) -> Float { return x }
357+
358+
func rdar20233198() {
359+
let typed: (Int, Int, Int, Int, Int, Int, Int, Int) = (Int(1), Int(1), Int(1), Int(1), Int(1), Int(1), Int(1), Int(1))
360+
_ = typed
361+
let _ = (Int(1), Int(1), Int(1), Int(1), Int(1), Int(1), Int(1), Int(1))
362+
let named = (Int(1), Int(1), Int(1), Int(1), Int(1), Int(1), Int(1), Int(1))
363+
_ = named;
364+
let _ = (overload(1), overload(1), overload(1), overload(1), overload(1), overload(1), overload(1), overload(1))
365+
let _ = (overload(1.0), overload(1.0), overload(1.0), overload(1.0), overload(1.0), overload(1.0), overload(1.0), overload(1.0))
366+
}

test/decl/var/variables.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func tuplePatternDestructuring(_ x : Int, y : Int) {
8282
_ = i+j
8383

8484
// <rdar://problem/20395243> QoI: type variable reconstruction failing for tuple types
85-
let (x: g1, a: h1) = (b: x, a: y) // expected-error {{tuple type '(b: Int, a: Int)' is not convertible to tuple '(x: _, a: _)'}}
85+
let (x: g1, a: h1) = (b: x, a: y) // expected-error {{tuple type '(b: Int, a: Int)' is not convertible to tuple '(x: Int, a: Int)'}}
8686
}
8787

8888
// <rdar://problem/21057425> Crash while compiling attached test-app.

validation-test/Sema/type_checker_perf/slow/rdar20233198.swift.gyb renamed to validation-test/Sema/type_checker_perf/fast/rdar20233198.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %scale-test --invert-result --begin 1 --end 5 --step 1 --select incrementScopeCounter %s
1+
// RUN: %scale-test --begin 1 --end 5 --step 1 --select incrementScopeCounter %s
22
// REQUIRES: OS=macosx
33
// REQUIRES: asserts
44

0 commit comments

Comments
 (0)