Skip to content

Commit eaa737c

Browse files
committed
[TypeChecker] Allow inference from default even when type could be inferred from result as well
This enables support for inference in initializers of generic types and in `case`s of generic enums e.g. ``` struct S<T> { init(_: T = 42) {} } enum E<T: Collection> { case test(_: T = [42]) } ```
1 parent 82b955b commit eaa737c

File tree

4 files changed

+72
-16
lines changed

4 files changed

+72
-16
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6244,11 +6244,6 @@ ERROR(type_sequence_on_non_generic_param, none,
62446244
// MARK: Type inference from default expressions
62456245
//------------------------------------------------------------------------------
62466246

6247-
ERROR(cannot_default_generic_parameter_inferrable_from_result, none,
6248-
"cannot use default expression for inference of %0 because it "
6249-
"is inferrable from result type",
6250-
(Type))
6251-
62526247
ERROR(cannot_default_generic_parameter_inferrable_from_another_parameter, none,
62536248
"cannot use default expression for inference of %0 because it "
62546249
"is inferrable from parameters %1",

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -535,15 +535,6 @@ Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue,
535535
{
536536
auto anchorTy = anchor->getInterfaceType()->castTo<GenericFunctionType>();
537537

538-
// Reject if generic parameters could be inferred from result type.
539-
if (containsTypes(anchorTy->getResult(), genericParameters)) {
540-
ctx.Diags.diagnose(
541-
defaultValue->getLoc(),
542-
diag::cannot_default_generic_parameter_inferrable_from_result,
543-
paramInterfaceTy);
544-
return Type();
545-
}
546-
547538
// Reject if generic parameters are used in multiple different positions
548539
// in the parameter list.
549540

test/Constraints/type_inference_from_default_exprs.swift

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/InferViaDefaults.swiftmodule -enable-experimental-type-inference-from-defaults -module-name InferViaDefaults %S/Inputs/type_inference_via_defaults_other_module.swift
33
// RUN: %target-swift-frontend -enable-experimental-type-inference-from-defaults -module-name main -typecheck -verify -I %t %s %S/Inputs/type_inference_via_defaults_other_module.swift
44

5-
func testInferFromResult<T>(_: T = 42) -> T { fatalError() }
6-
// expected-error@-1 {{cannot use default expression for inference of 'T' because it is inferrable from result type}}
5+
func testInferFromResult<T>(_: T = 42) -> T { fatalError() } // Ok
6+
7+
enum ETest<T> {
8+
case test(_: T = 42) // expected-note {{default value declared here}}
9+
}
710

811
func testInferFromOtherPos1<T>(_: T = 42, _: [T]) {}
912
// expected-error@-1 {{cannot use default expression for inference of 'T' because it is inferrable from parameters #0, #1}}
@@ -101,7 +104,27 @@ func testReq2<T, U>(_: (T, U) = (E(), B())) where T: GenClass<U>, U: AnyObject {
101104
func testReq3<T: P, U>(_: [T?] = [B()], _: U) where T.X == U {}
102105
// expected-error@-1 {{cannot use default expression for inference of '[T?]' because requirement 'U == T.X' refers to other generic parameters}}
103106

107+
protocol Shape {
108+
}
109+
110+
struct Circle : Shape {
111+
}
112+
113+
struct Rectangle : Shape {
114+
}
115+
116+
struct Figure<S: Shape> {
117+
init(_: S = Circle()) {} // expected-note 2 {{default value declared here}}
118+
}
119+
104120
func main() {
121+
_ = testInferFromResult() // Ok T == Int
122+
let _: Float = testInferFromResult() // expected-error {{cannot convert value of type 'Int' to specified type 'Float'}}
123+
124+
_ = ETest.test() // Ok
125+
126+
let _: ETest<String> = .test() // expected-error {{cannot convert default value of type 'String' to expected argument type 'Int' for parameter #0}}
127+
105128
test1() // Ok
106129

107130
test2() // Ok
@@ -129,4 +152,18 @@ func main() {
129152
testNested6() // Ok
130153

131154
testReq2() // Ok
155+
156+
func takesFigure<T>(_: Figure<T>) {}
157+
func takesCircle(_: Figure<Circle>) {}
158+
func takesRectangle(_: Figure<Rectangle>) {}
159+
160+
_ = Figure.init() // Ok S == Circle
161+
let _: Figure<Circle> = .init() // Ok (S == Circle)
162+
let _: Figure<Rectangle> = .init()
163+
// expected-error@-1 {{cannot convert default value of type 'Rectangle' to expected argument type 'Circle' for parameter #0}}
164+
165+
takesFigure(.init()) // Ok
166+
takesCircle(.init()) // Ok
167+
takesRectangle(.init())
168+
// expected-error@-1 {{cannot convert default value of type 'Rectangle' to expected argument type 'Circle' for parameter #0}}
132169
}

test/Constraints/type_inference_from_default_exprs_executable_test.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,25 @@ struct OtherD : P {
9999
typealias X = OtherB
100100
}
101101

102+
protocol Shape {
103+
}
104+
105+
struct Circle : Shape {
106+
}
107+
108+
struct Rectangle : Shape {
109+
}
110+
111+
struct Figure<S: Shape> {
112+
init(v: S = Circle()) {
113+
print("Figure: \(v); type = \(type(of: v))")
114+
}
115+
}
116+
117+
enum TestE<T: Collection> {
118+
case a(_: T = [B()])
119+
}
120+
102121
func run_tests() {
103122
test1()
104123
// CHECK: test1: 42; type = Int
@@ -159,6 +178,20 @@ func run_tests() {
159178

160179
testReq1()
161180
// CHECK: testReq1: (main.E, main.B); type = (E, B)
181+
182+
_ = Figure.init()
183+
// CHECK: Figure: Circle(); type = Circle
184+
let _: Figure<Circle> = .init()
185+
// CHECK: Figure: Circle(); type = Circle
186+
187+
func takesFigure<T>(_: Figure<T>) {}
188+
189+
takesFigure(.init())
190+
// CHECK: Figure: Circle(); type = Circle
191+
192+
let e: TestE = .a()
193+
print("ETEst: \(e); type = \(type(of: e))")
194+
// CHECK: ETEst: a([main.B]); type = TestE<Array<B>>
162195
}
163196

164197
@main struct Test {

0 commit comments

Comments
 (0)