Skip to content

Commit 1a1bff4

Browse files
committed
[CS] Don't crash when using magic literals as default arg
Squash all commits into one
1 parent 62a37d7 commit 1a1bff4

File tree

10 files changed

+131
-2
lines changed

10 files changed

+131
-2
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ ERROR(cannot_convert_default_arg_value,none,
350350
(Type,Type))
351351
ERROR(cannot_convert_default_arg_value_protocol,none,
352352
"default argument value of type %0 does not conform to %1", (Type,Type))
353+
ERROR(default_argument_literal_cannot_convert, none,
354+
"cannot call %0 %1 because default argument of type %2 cannot be "
355+
"converted to type %3", (DescriptiveDeclKind, DeclName, Type, Type))
353356
ERROR(cannot_convert_default_arg_value_nil,none,
354357
"nil default argument value cannot be converted to type %0", (Type))
355358

lib/Sema/CSDiagnostics.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2710,6 +2710,21 @@ bool MissingArgumentsFailure::diagnoseTrailingClosure(ClosureExpr *closure) {
27102710
return true;
27112711
}
27122712

2713+
bool DefaultArgumentTypeMismatch::diagnoseAsError() {
2714+
auto choice = getChoiceFor(getRawAnchor());
2715+
if (!choice.hasValue())
2716+
return false;
2717+
2718+
auto declName = choice.getValue().choice.getName();
2719+
auto declKind = choice.getValue().choice.getDecl()->getDescriptiveKind();
2720+
2721+
emitDiagnostic(getAnchor()->getLoc(),
2722+
diag::default_argument_literal_cannot_convert, declKind,
2723+
declName, FromType, ToType);
2724+
2725+
return true;
2726+
}
2727+
27132728
bool ClosureParamDestructuringFailure::diagnoseAsError() {
27142729
auto *closure = cast<ClosureExpr>(getAnchor());
27152730
auto params = closure->getParameters();

lib/Sema/CSDiagnostics.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,21 @@ class MissingArgumentsFailure final : public FailureDiagnostic {
10791079
bool diagnoseTrailingClosure(ClosureExpr *closure);
10801080
};
10811081

1082+
class DefaultArgumentTypeMismatch final : public FailureDiagnostic {
1083+
using Param = AnyFunctionType::Param;
1084+
1085+
Type FromType;
1086+
Type ToType;
1087+
1088+
public:
1089+
DefaultArgumentTypeMismatch(Expr *root, ConstraintSystem &cs, Type fromType,
1090+
Type toType, ConstraintLocator *locator)
1091+
: FailureDiagnostic(root, cs, locator), FromType(fromType),
1092+
ToType(toType) {}
1093+
1094+
bool diagnoseAsError() override;
1095+
};
1096+
10821097
class OutOfOrderArgumentFailure final : public FailureDiagnostic {
10831098
using ParamBinding = SmallVector<unsigned, 1>;
10841099

lib/Sema/CSFix.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,21 @@ bool AddMissingArguments::diagnose(Expr *root, bool asNote) const {
451451
return failure.diagnose(asNote);
452452
}
453453

454+
IgnoreDefaultArgumentTypeMismatch *
455+
IgnoreDefaultArgumentTypeMismatch::create(ConstraintSystem &cs, Type fromType,
456+
Type toType,
457+
ConstraintLocator *locator) {
458+
return new (cs.getAllocator())
459+
IgnoreDefaultArgumentTypeMismatch(cs, fromType, toType, locator);
460+
}
461+
462+
bool IgnoreDefaultArgumentTypeMismatch::diagnose(Expr *root,
463+
bool asNote) const {
464+
DefaultArgumentTypeMismatch failure(root, getConstraintSystem(), FromType,
465+
ToType, getLocator());
466+
return failure.diagnose(asNote);
467+
}
468+
454469
AddMissingArguments *
455470
AddMissingArguments::create(ConstraintSystem &cs, FunctionType *funcType,
456471
llvm::ArrayRef<Param> synthesizedArgs,

lib/Sema/CSFix.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,9 @@ enum class FixKind : uint8_t {
183183
/// Allow invalid reference to a member declared as `mutating`
184184
/// when base is an r-value type.
185185
AllowMutatingMemberOnRValueBase,
186+
187+
/// Fix the type of the default argument
188+
DefaultArgumentTypeMismatch,
186189
};
187190

188191
class ConstraintFix {
@@ -941,6 +944,27 @@ class AddMissingArguments final
941944
}
942945
};
943946

947+
class IgnoreDefaultArgumentTypeMismatch final : public ConstraintFix {
948+
Type FromType;
949+
Type ToType;
950+
951+
IgnoreDefaultArgumentTypeMismatch(ConstraintSystem &cs, Type fromType,
952+
Type toType, ConstraintLocator *locator)
953+
: ConstraintFix(cs, FixKind::DefaultArgumentTypeMismatch, locator),
954+
FromType(fromType), ToType(toType) {}
955+
956+
public:
957+
std::string getName() const override {
958+
return "ignore default argument type mismatch";
959+
}
960+
961+
bool diagnose(Expr *root, bool asNote = false) const override;
962+
963+
static IgnoreDefaultArgumentTypeMismatch *create(ConstraintSystem &cs,
964+
Type fromType, Type toType,
965+
ConstraintLocator *locator);
966+
};
967+
944968
class MoveOutOfOrderArgument final : public ConstraintFix {
945969
using ParamBinding = SmallVector<unsigned, 1>;
946970

lib/Sema/CSSimplify.cpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -960,9 +960,36 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
960960

961961
for (unsigned paramIdx = 0, numParams = parameterBindings.size();
962962
paramIdx != numParams; ++paramIdx){
963-
// Skip unfulfilled parameters. There's nothing to do for them.
964-
if (parameterBindings[paramIdx].empty())
963+
// If a parameter is unfulfilled, validate the default argument if it is a
964+
// magic literal expression.
965+
if (parameterBindings[paramIdx].empty()) {
966+
if (!callee)
967+
continue;
968+
969+
if (!callee->hasParameterList())
970+
continue;
971+
972+
auto param = getParameterAt(callee, paramIdx);
973+
974+
auto defaultValueExpr = param->getDefaultValue();
975+
976+
if (!(defaultValueExpr &&
977+
isa<MagicIdentifierLiteralExpr>(defaultValueExpr)))
978+
continue;
979+
980+
if (defaultValueExpr->getType())
981+
continue;
982+
983+
cs.generateConstraints(defaultValueExpr, param->getDeclContext());
984+
985+
auto defaultTy = cs.getType(defaultValueExpr);
986+
auto paramTy = param->getType();
987+
cs.addConstraint(
988+
ConstraintKind::ArgumentConversion, defaultTy, paramTy,
989+
locator.withPathElement(ConstraintLocator::DefaultArgument));
990+
965991
continue;
992+
}
966993

967994
// Determine the parameter type.
968995
const auto &param = params[paramIdx];
@@ -2329,6 +2356,12 @@ bool ConstraintSystem::repairFailures(
23292356
break;
23302357
}
23312358

2359+
case ConstraintLocator::DefaultArgument: {
2360+
conversionsOrFixes.push_back(IgnoreDefaultArgumentTypeMismatch::create(
2361+
*this, lhs, rhs, getConstraintLocator(anchor, path)));
2362+
break;
2363+
}
2364+
23322365
case ConstraintLocator::TypeParameterRequirement:
23332366
case ConstraintLocator::ConditionalRequirement: {
23342367
// If dependent members are present here it's because
@@ -6959,6 +6992,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
69596992
case FixKind::SkipSuperclassRequirement:
69606993
case FixKind::ContextualMismatch:
69616994
case FixKind::AddMissingArguments:
6995+
case FixKind::DefaultArgumentTypeMismatch:
69626996
case FixKind::SkipUnhandledConstructInFunctionBuilder:
69636997
case FixKind::UsePropertyWrapper:
69646998
case FixKind::UseWrappedValue: {

lib/Sema/ConstraintLocator.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, Expr *anchor,
5252
case ApplyArgument:
5353
case ApplyFunction:
5454
case FunctionArgument:
55+
case DefaultArgument:
5556
case FunctionResult:
5657
case OptionalPayload:
5758
case Member:
@@ -270,6 +271,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) {
270271
out << "function argument";
271272
break;
272273

274+
case DefaultArgument:
275+
out << "default argument";
276+
break;
277+
273278
case FunctionResult:
274279
out << "function result";
275280
break;

lib/Sema/ConstraintLocator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class ConstraintLocator : public llvm::FoldingSetNode {
6565
GenericParameter,
6666
/// The argument type of a function.
6767
FunctionArgument,
68+
/// The default argument type of a function.
69+
DefaultArgument,
6870
/// The result type of a function.
6971
FunctionResult,
7072
/// A tuple element referenced by position.
@@ -147,6 +149,7 @@ class ConstraintLocator : public llvm::FoldingSetNode {
147149
case ApplyFunction:
148150
case GenericParameter:
149151
case FunctionArgument:
152+
case DefaultArgument:
150153
case FunctionResult:
151154
case OptionalPayload:
152155
case Member:
@@ -244,6 +247,7 @@ class ConstraintLocator : public llvm::FoldingSetNode {
244247
return 0;
245248

246249
case FunctionArgument:
250+
case DefaultArgument:
247251
case FunctionResult:
248252
return IsFunctionConversion;
249253
}

test/decl/func/default-values.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,12 @@ let fooThing5 = Foo(a: 0, d: 1, h: nil) // expected-error {{missing argument for
168168
// Here b = false and g = nil, but we're checking that f doesn't get a default value
169169
let fooThing6 = Foo(a: 0, d: 1, e: 2, h: nil) // expected-error {{missing argument for parameter 'f' in call}}
170170
// expected-note@-29 {{'init(a:b:d:e:f:g:h:)' declared here}}
171+
172+
// SR-11074
173+
174+
func sr_11074(x: Int) {}
175+
func sr_11074(line: String = #line) {} // expected-error {{default argument value of type 'Int' cannot be converted to type 'String'}}
176+
sr_11074() // expected-error {{cannot call global function 'sr_11074(line:)' because default argument of type 'Int' cannot be converted to type 'String'}}
177+
178+
class SR_11074_C { init(line: String = #line) {} } // expected-error {{default argument value of type 'Int' cannot be converted to type 'String'}}
179+
let _ = SR_11074_C() // expected-error {{cannot call initializer 'init(line:)' because default argument of type 'Int' cannot be converted to type 'String'}}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: not %target-swift-frontend -typecheck %s
2+
3+
func foo(x: Int) {}
4+
func foo(line: String = #line) {}
5+
foo()

0 commit comments

Comments
 (0)