Skip to content

Commit 379b0db

Browse files
akyrtzitkremenek
authored andcommitted
[sema] Add a fixit for missing generic arguments. (#2867)
When the unbound generic type is missing type arguments try to add a fixit that infers a generic type list to pass. rdar://26623703
1 parent 3973057 commit 379b0db

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,11 +562,50 @@ static Type applyGenericTypeReprArgs(TypeChecker &TC, Type type, SourceLoc loc,
562562

563563
/// \brief Diagnose a use of an unbound generic type.
564564
static void diagnoseUnboundGenericType(TypeChecker &tc, Type ty,SourceLoc loc) {
565-
tc.diagnose(loc, diag::generic_type_requires_arguments, ty);
566565
auto unbound = ty->castTo<UnboundGenericType>();
566+
{
567+
InFlightDiagnostic diag = tc.diagnose(loc,
568+
diag::generic_type_requires_arguments, ty);
569+
if (auto *genericD = unbound->getDecl()) {
570+
571+
// Tries to infer the type arguments to pass.
572+
// Currently it only works if all the generic arguments have a super type,
573+
// or it requires a class, in which case it infers 'AnyObject'.
574+
auto inferGenericArgs = [](GenericTypeDecl *genericD)->std::string {
575+
GenericParamList *genParamList = genericD->getGenericParams();
576+
if (!genParamList)
577+
return std::string();
578+
auto params= genParamList->getParams();
579+
if (params.empty())
580+
return std::string();
581+
std::string argsToAdd = "<";
582+
for (unsigned i = 0, e = params.size(); i != e; ++i) {
583+
auto param = params[i];
584+
auto archTy = param->getArchetype();
585+
if (!archTy)
586+
return std::string();
587+
if (auto superTy = archTy->getSuperclass()) {
588+
argsToAdd += superTy.getString();
589+
} else if (archTy->requiresClass()) {
590+
argsToAdd += "AnyObject";
591+
} else {
592+
return std::string(); // give up.
593+
}
594+
if (i < e-1)
595+
argsToAdd += ", ";
596+
}
597+
argsToAdd += ">";
598+
return argsToAdd;
599+
};
600+
601+
std::string genericArgsToAdd = inferGenericArgs(genericD);
602+
if (!genericArgsToAdd.empty()) {
603+
diag.fixItInsertAfter(loc, genericArgsToAdd);
604+
}
605+
}
606+
}
567607
tc.diagnose(unbound->getDecl()->getLoc(), diag::generic_type_declared_here,
568608
unbound->getDecl()->getName());
569-
// TODO: emit fixit for "NSArray" -> "NSArray<AnyObject>", etc.
570609
}
571610

572611
/// \brief Returns a valid type or ErrorType in case of an error.

test/FixCode/fixits-apply.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,18 @@ func letToVar1() {
127127
y.append("as")
128128
y.append("df")
129129
}
130+
131+
class Node {}
132+
class Graph<NodeType : Node> {}
133+
var graph: Graph
134+
135+
class Node2 {}
136+
class Graph2<NodeType1 : Node, NodeType2 : Node2> {}
137+
var graph: Graph2
138+
139+
@objc protocol ObjCProt { }
140+
class Graph3<NodeType : ObjCProt> {}
141+
var graph: Graph3
142+
143+
class GraphNoFix<NodeType : SomeProt> {}
144+
var graph: GraphNoFix

test/FixCode/fixits-apply.swift.result

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,18 @@ func letToVar1() {
130130
y.append("as")
131131
y.append("df")
132132
}
133+
134+
class Node {}
135+
class Graph<NodeType : Node> {}
136+
var graph: Graph<Node>
137+
138+
class Node2 {}
139+
class Graph2<NodeType1 : Node, NodeType2 : Node2> {}
140+
var graph: Graph2<Node, Node2>
141+
142+
@objc protocol ObjCProt { }
143+
class Graph3<NodeType : ObjCProt> {}
144+
var graph: Graph3<AnyObject>
145+
146+
class GraphNoFix<NodeType : SomeProt> {}
147+
var graph: GraphNoFix

0 commit comments

Comments
 (0)