Skip to content

Commit 1d7ad9e

Browse files
committed
Better generic fix-its for types as well as construction and casts.
Slava pointed out that we have an existing version of the code from the previous commit that's only used when checking types. Replace it with the new code, which handles more cases.
1 parent caeed32 commit 1d7ad9e

File tree

4 files changed

+61
-46
lines changed

4 files changed

+61
-46
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -624,42 +624,9 @@ static void diagnoseUnboundGenericType(TypeChecker &tc, Type ty,SourceLoc loc) {
624624
InFlightDiagnostic diag = tc.diagnose(loc,
625625
diag::generic_type_requires_arguments, ty);
626626
if (auto *genericD = unbound->getDecl()) {
627-
628-
// Tries to infer the type arguments to pass.
629-
// Currently it only works if all the generic arguments have a super type,
630-
// or it requires a class, in which case it infers 'AnyObject'.
631-
auto inferGenericArgs = [](GenericTypeDecl *genericD)->std::string {
632-
auto *mod = genericD->getParentModule();
633-
auto *genericSig = genericD->getGenericSignature();
634-
if (!genericSig)
635-
return std::string();
636-
637-
auto params = genericSig->getInnermostGenericParams();
638-
if (params.empty())
639-
return std::string();
640-
std::string argsToAdd = "<";
641-
for (unsigned i = 0, e = params.size(); i != e; ++i) {
642-
auto param = params[i];
643-
if (auto superTy = genericSig->getSuperclassBound(param, *mod)) {
644-
if (superTy->hasTypeParameter())
645-
return std::string(); // give up
646-
argsToAdd += superTy.getString();
647-
} else if (genericSig->requiresClass(param, *mod)) {
648-
argsToAdd += "AnyObject";
649-
} else {
650-
return std::string(); // give up.
651-
}
652-
if (i < e-1)
653-
argsToAdd += ", ";
654-
}
655-
argsToAdd += ">";
656-
return argsToAdd;
657-
};
658-
659-
std::string genericArgsToAdd = inferGenericArgs(genericD);
660-
if (!genericArgsToAdd.empty()) {
627+
SmallString<64> genericArgsToAdd;
628+
if (tc.getDefaultGenericArgumentsString(genericArgsToAdd, genericD))
661629
diag.fixItInsertAfter(loc, genericArgsToAdd);
662-
}
663630
}
664631
}
665632
tc.diagnose(unbound->getDecl()->getLoc(), diag::generic_type_declared_here,

test/Constraints/generics.swift

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func generic_metatypes<T : SomeProtocol>(_ x: T)
5454
// Inferring a variable's type from a call to a generic.
5555
struct Pair<T, U> { } // expected-note 5 {{'T' declared as parameter to type 'Pair'}}
5656

57-
func pair<T, U>(_ x: T, _ y: U) -> Pair<T, U> { }
57+
func pair<T, U>(_ x: T, _ y: U) -> Pair<T, U> { } // expected-note 3 {{in call to function 'pair'}}
5858

5959
var i : Int, f : Float
6060
var p = pair(i, f)
@@ -260,21 +260,21 @@ protocol SubProto: BaseProto {}
260260
func copy() -> Any
261261
}
262262

263-
struct FullyGeneric<Foo> {} // expected-note 2 {{'Foo' declared as parameter to type 'FullyGeneric'}}
263+
struct FullyGeneric<Foo> {} // expected-note 3 {{'Foo' declared as parameter to type 'FullyGeneric'}} expected-note 6 {{generic type 'FullyGeneric' declared here}}
264264

265-
struct AnyClassBound<Foo: AnyObject> {} // expected-note {{'Foo' declared as parameter to type 'AnyClassBound'}}
265+
struct AnyClassBound<Foo: AnyObject> {} // expected-note {{'Foo' declared as parameter to type 'AnyClassBound'}} expected-note {{generic type 'AnyClassBound' declared here}}
266266
struct AnyClassBound2<Foo> where Foo: AnyObject {} // expected-note {{'Foo' declared as parameter to type 'AnyClassBound2'}}
267267

268-
struct ProtoBound<Foo: SubProto> {} // expected-note {{'Foo' declared as parameter to type 'ProtoBound'}}
268+
struct ProtoBound<Foo: SubProto> {} // expected-note {{'Foo' declared as parameter to type 'ProtoBound'}} expected-note {{generic type 'ProtoBound' declared here}}
269269
struct ProtoBound2<Foo> where Foo: SubProto {} // expected-note {{'Foo' declared as parameter to type 'ProtoBound2'}}
270270

271-
struct ObjCProtoBound<Foo: NSCopyish> {} // expected-note {{'Foo' declared as parameter to type 'ObjCProtoBound'}}
271+
struct ObjCProtoBound<Foo: NSCopyish> {} // expected-note {{'Foo' declared as parameter to type 'ObjCProtoBound'}} expected-note {{generic type 'ObjCProtoBound' declared here}}
272272
struct ObjCProtoBound2<Foo> where Foo: NSCopyish {} // expected-note {{'Foo' declared as parameter to type 'ObjCProtoBound2'}}
273273

274274
struct ClassBound<Foo: X> {} // expected-note {{generic type 'ClassBound' declared here}}
275275
struct ClassBound2<Foo> where Foo: X {} // expected-note {{generic type 'ClassBound2' declared here}}
276276

277-
struct ProtosBound<Foo> where Foo: SubProto & NSCopyish {} // expected-note {{'Foo' declared as parameter to type 'ProtosBound'}}
277+
struct ProtosBound<Foo> where Foo: SubProto & NSCopyish {} // expected-note {{'Foo' declared as parameter to type 'ProtosBound'}} expected-note {{generic type 'ProtosBound' declared here}}
278278
struct ProtosBound2<Foo: SubProto & NSCopyish> {} // expected-note {{'Foo' declared as parameter to type 'ProtosBound2'}}
279279
struct ProtosBound3<Foo: SubProto> where Foo: NSCopyish {} // expected-note {{'Foo' declared as parameter to type 'ProtosBound3'}}
280280

@@ -360,3 +360,45 @@ func testFixItContextualKnowledge() {
360360
let _: Int = Pair().first // expected-error {{generic parameter 'T' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{20-20=<Any, Any>}}
361361
let _: Int = Pair().second // expected-error {{generic parameter 'T' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{20-20=<Any, Any>}}
362362
}
363+
364+
func testFixItTypePosition() {
365+
let _: FullyGeneric // expected-error {{reference to generic type 'FullyGeneric' requires arguments in <...>}} {{22-22=<Any>}}
366+
let _: ProtoBound // expected-error {{reference to generic type 'ProtoBound' requires arguments in <...>}} {{20-20=<<#Foo: SubProto#>>}}
367+
let _: ObjCProtoBound // expected-error {{reference to generic type 'ObjCProtoBound' requires arguments in <...>}} {{24-24=<NSCopyish>}}
368+
let _: AnyClassBound // expected-error {{reference to generic type 'AnyClassBound' requires arguments in <...>}} {{23-23=<AnyObject>}}
369+
let _: ProtosBound // expected-error {{reference to generic type 'ProtosBound' requires arguments in <...>}} {{21-21=<<#Foo: NSCopyish & SubProto#>>}}
370+
}
371+
372+
func testFixItNested() {
373+
_ = Array<FullyGeneric>() // expected-error {{reference to generic type 'FullyGeneric' requires arguments in <...>}} {{25-25=<Any>}}
374+
_ = [FullyGeneric]() // expected-error {{generic parameter 'Foo' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{20-20=<Any>}}
375+
376+
_ = FullyGeneric<FullyGeneric>() // expected-error {{reference to generic type 'FullyGeneric' requires arguments in <...>}} {{32-32=<Any>}}
377+
378+
_ = Pair<
379+
FullyGeneric, // expected-error {{reference to generic type 'FullyGeneric' requires arguments in <...>}} {{17-17=<Any>}}
380+
FullyGeneric // FIXME: We could diagnose both of these, but we don't.
381+
>()
382+
_ = Pair<
383+
FullyGeneric<Any>,
384+
FullyGeneric // expected-error {{reference to generic type 'FullyGeneric' requires arguments in <...>}} {{17-17=<Any>}}
385+
>()
386+
_ = Pair<
387+
FullyGeneric, // expected-error {{reference to generic type 'FullyGeneric' requires arguments in <...>}} {{17-17=<Any>}}
388+
FullyGeneric<Any>
389+
>()
390+
391+
// FIXME: These errors could be improved.
392+
_ = pair( // expected-error {{generic parameter 'T' could not be inferred}} {{none}}
393+
FullyGeneric(),
394+
FullyGeneric()
395+
)
396+
_ = pair( // expected-error {{generic parameter 'T' could not be inferred}} {{none}}
397+
FullyGeneric<Any>(),
398+
FullyGeneric()
399+
)
400+
_ = pair( // expected-error {{generic parameter 'T' could not be inferred}} {{none}}
401+
FullyGeneric(),
402+
FullyGeneric<Any>()
403+
)
404+
}

test/FixCode/fixits-apply.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,11 @@ var graph: Graph2
187187
class Graph3<NodeType : ObjCProt> {}
188188
var graph: Graph3
189189

190-
class GraphNoFix<NodeType : SomeProt> {}
191-
var graph: GraphNoFix
190+
class Graph4<NodeType : SomeProt> {}
191+
var graph: Graph4
192+
193+
class GraphCombo<NodeType : SomeProt & ObjCProt> {}
194+
var graph: GraphCombo
192195

193196
func evilCommas(s: String) {
194197
_ = s[s.startIndex..<<#editorplaceholder#>]

test/FixCode/fixits-apply.swift.result

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,13 @@ var graph: Graph2<Node, Node2>
188188

189189
@objc protocol ObjCProt { }
190190
class Graph3<NodeType : ObjCProt> {}
191-
var graph: Graph3<AnyObject>
191+
var graph: Graph3<ObjCProt>
192192

193-
class GraphNoFix<NodeType : SomeProt> {}
194-
var graph: GraphNoFix
193+
class Graph4<NodeType : SomeProt> {}
194+
var graph: Graph4<<#NodeType: SomeProt#>>
195+
196+
class GraphCombo<NodeType : SomeProt & ObjCProt> {}
197+
var graph: GraphCombo<<#NodeType: ObjCProt & SomeProt#>>
195198

196199
func evilCommas(s: String) {
197200
_ = s[s.startIndex..<<#editorplaceholder#>]

0 commit comments

Comments
 (0)