Skip to content

Commit 792ab3c

Browse files
committed
[sema] Add compiler fixit for the case where a raw-representable type is constructed from an argument with the same type.
Like this: MyEnumType(MyEnumType.foo) This is missing 'rawValue:' label, but that won't actually fix this. A better fix is to just remove the unnecessary constructor call: MyEnumType(MyEnumType.foo) --> MyEnumType.foo
1 parent 2e9455f commit 792ab3c

File tree

4 files changed

+62
-3
lines changed

4 files changed

+62
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,9 @@ ERROR(instance_member_in_initializer,none,
758758
"cannot use instance member %0 within property initializer; "
759759
"property initializers run before 'self' is available", (DeclName))
760760

761+
ERROR(invalid_initialization_parameter_same_type,none,
762+
"invalid initializer call with same type %0 as parameter", (Type))
763+
761764
ERROR(missing_argument_named,none,
762765
"missing argument for parameter %0 in call", (Identifier))
763766
ERROR(missing_argument_positional,none,

lib/Sema/CSDiag.cpp

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3099,10 +3099,8 @@ static bool isIntegerType(Type fromType, ConstraintSystem *CS) {
30993099
CS);
31003100
}
31013101

3102-
/// Return true if the given type conforms to RawRepresentable, with an
3103-
/// underlying type conforming to the given known protocol.
3102+
/// Return true if the given type conforms to RawRepresentable.
31043103
static Type isRawRepresentable(Type fromType,
3105-
KnownProtocolKind kind,
31063104
ConstraintSystem *CS) {
31073105
auto rawReprType =
31083106
CS->TC.getProtocol(SourceLoc(), KnownProtocolKind::RawRepresentable);
@@ -3119,6 +3117,15 @@ static Type isRawRepresentable(Type fromType,
31193117
conformance,
31203118
CS->getASTContext().getIdentifier("RawValue"),
31213119
&CS->TC);
3120+
return rawTy;
3121+
}
3122+
3123+
/// Return true if the given type conforms to RawRepresentable, with an
3124+
/// underlying type conforming to the given known protocol.
3125+
static Type isRawRepresentable(Type fromType,
3126+
KnownProtocolKind kind,
3127+
ConstraintSystem *CS) {
3128+
Type rawTy = isRawRepresentable(fromType, CS);
31223129
if (!rawTy || !isLiteralConvertibleType(rawTy, kind, CS))
31233130
return Type();
31243131

@@ -3800,6 +3807,45 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
38003807
}
38013808
}
38023809

3810+
// Check the case where a raw-representable type is constructed from an
3811+
// argument with the same type:
3812+
//
3813+
// MyEnumType(MyEnumType.foo)
3814+
//
3815+
// This is missing 'rawValue:' label, but a better fix is to just remove the
3816+
// unnecessary constructor call:
3817+
//
3818+
// MyEnumType.foo
3819+
//
3820+
if (params.size() == 1 && args.size() == 1 &&
3821+
candidate.getDecl() && isa<ConstructorDecl>(candidate.getDecl()) &&
3822+
candidate.level == 1) {
3823+
CallArgParam &arg = args[0];
3824+
auto resTy = candidate.getResultType();
3825+
if (auto unwrappedOpt = resTy->getOptionalObjectType())
3826+
resTy = unwrappedOpt;
3827+
auto rawTy = isRawRepresentable(resTy, CCI.CS);
3828+
if (rawTy && resTy->getCanonicalType() == arg.Ty.getCanonicalTypeOrNull()) {
3829+
auto getInnerExpr = [](Expr *E) -> Expr* {
3830+
ParenExpr *parenE = dyn_cast<ParenExpr>(E);
3831+
if (!parenE)
3832+
return nullptr;
3833+
return parenE->getSubExpr();
3834+
};
3835+
Expr *innerE = getInnerExpr(argExpr);
3836+
3837+
InFlightDiagnostic diag = TC.diagnose(fnExpr->getLoc(),
3838+
diag::invalid_initialization_parameter_same_type, resTy);
3839+
diag.highlight((innerE ? innerE : argExpr)->getSourceRange());
3840+
if (innerE) {
3841+
// Remove the unnecessary constructor call.
3842+
diag.fixItRemoveChars(fnExpr->getLoc(), innerE->getStartLoc())
3843+
.fixItRemove(argExpr->getEndLoc());
3844+
}
3845+
return true;
3846+
}
3847+
}
3848+
38033849
// We only handle structural errors here.
38043850
if (CCI.closeness != CC_ArgumentLabelMismatch &&
38053851
CCI.closeness != CC_ArgumentCountMismatch)

test/FixCode/fixits-apply.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ func testMask4(a: MyEventMask2) {
4949
testMask2(a: a)
5050
}
5151

52+
enum MyEnumType : UInt32 {
53+
case invalid
54+
}
55+
_ = MyEnumType(MyEnumType.invalid)
56+
5257
func goo(var e : ErrorProtocol) {
5358
}
5459
func goo2(var e: ErrorProtocol) {}

test/FixCode/fixits-apply.swift.result

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ func testMask4(a: MyEventMask2) {
4949
testMask2(a: a.rawValue)
5050
}
5151

52+
enum MyEnumType : UInt32 {
53+
case invalid
54+
}
55+
_ = MyEnumType.invalid
56+
5257
func goo(e : ErrorProtocol) {
5358
var e = e
5459
}

0 commit comments

Comments
 (0)