Skip to content

Commit b2be3b3

Browse files
authored
Merge pull request #3579 from rudkx/fix-27013358
Fix crash when using instance member as default parameter.
2 parents 9741db1 + ee6c0a7 commit b2be3b3

File tree

3 files changed

+77
-14
lines changed

3 files changed

+77
-14
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,8 @@ ERROR(instance_member_use_on_type,none,
768768
ERROR(instance_member_in_initializer,none,
769769
"cannot use instance member %0 within property initializer; "
770770
"property initializers run before 'self' is available", (DeclName))
771+
ERROR(instance_member_in_default_parameter,none,
772+
"cannot use instance member %0 as a default parameter", (DeclName))
771773

772774
ERROR(invalid_initialization_parameter_same_type,none,
773775
"invalid initializer call with same type %0 as parameter", (Type))

lib/Sema/CSDiag.cpp

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2306,18 +2306,48 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
23062306
return;
23072307
case MemberLookupResult::UR_InstanceMemberOnType:
23082308
// If the base is an implicit self type reference, and we're in a
2309-
// property initializer, then the user wrote something like:
2309+
// an initializer, then the user wrote something like:
23102310
//
23112311
// class Foo { let x = 1, y = x }
23122312
//
2313-
// which runs in type context, not instance context. Produce a tailored
2314-
// diagnostic since this comes up and is otherwise non-obvious what is
2315-
// going on.
2316-
if (baseExpr && baseExpr->isImplicit() && isa<Initializer>(CS->DC) &&
2317-
CS->DC->getParent()->getDeclaredTypeOfContext()->isEqual(instanceTy)){
2318-
CS->TC.diagnose(nameLoc, diag::instance_member_in_initializer,
2319-
memberName);
2320-
return;
2313+
// which runs in type context, not instance context, or
2314+
//
2315+
// class Bar {
2316+
// let otherwise = 1 // instance member
2317+
// var x: Int
2318+
// func init(x: Int =otherwise) { // default parameter
2319+
// self.x = x
2320+
// }
2321+
// }
2322+
//
2323+
// in which an instance member is used as a default value for a
2324+
// parameter.
2325+
//
2326+
// Produce a tailored diagnostic for these cases since this
2327+
// comes up and is otherwise non-obvious what is going on.
2328+
if (baseExpr && baseExpr->isImplicit() && isa<Initializer>(CS->DC)) {
2329+
auto *TypeDC = CS->DC->getParent();
2330+
bool propertyInitializer = true;
2331+
// If the parent context is not a type context, we expect it
2332+
// to be a defaulted parameter in a function declaration.
2333+
if (!TypeDC->isTypeContext()) {
2334+
assert(TypeDC->getContextKind() ==
2335+
DeclContextKind::AbstractFunctionDecl &&
2336+
"Expected function decl context for initializer!");
2337+
TypeDC = TypeDC->getParent();
2338+
propertyInitializer = false;
2339+
}
2340+
assert(TypeDC->isTypeContext() && "Expected type decl context!");
2341+
2342+
if (TypeDC->getDeclaredTypeOfContext()->isEqual(instanceTy)) {
2343+
if (propertyInitializer)
2344+
CS->TC.diagnose(nameLoc, diag::instance_member_in_initializer,
2345+
memberName);
2346+
else
2347+
CS->TC.diagnose(nameLoc, diag::instance_member_in_default_parameter,
2348+
memberName);
2349+
return;
2350+
}
23212351
}
23222352

23232353
diagnose(loc, diag::could_not_use_instance_member_on_type,
@@ -4006,18 +4036,39 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
40064036
auto DC = CCI.CS->DC;
40074037

40084038
// If the base is an implicit self type reference, and we're in a
4009-
// property initializer, then the user wrote something like:
4039+
// an initializer, then the user wrote something like:
40104040
//
40114041
// class Foo { let val = initFn() }
4042+
// or
4043+
// class Bar { func something(x: Int = initFn()) }
40124044
//
40134045
// which runs in type context, not instance context. Produce a tailored
40144046
// diagnostic since this comes up and is otherwise non-obvious what is
40154047
// going on.
4016-
if (UDE->getBase()->isImplicit() && isa<Initializer>(DC) &&
4017-
DC->getParent()->getDeclaredTypeOfContext()->isEqual(baseType)){
4018-
TC.diagnose(UDE->getLoc(), diag::instance_member_in_initializer,
4048+
if (UDE->getBase()->isImplicit() && isa<Initializer>(DC)) {
4049+
auto *TypeDC = DC->getParent();
4050+
bool propertyInitializer = true;
4051+
// If the parent context is not a type context, we expect it
4052+
// to be a defaulted parameter in a function declaration.
4053+
if (!TypeDC->isTypeContext()) {
4054+
assert(TypeDC->getContextKind() ==
4055+
DeclContextKind::AbstractFunctionDecl &&
4056+
"Expected function decl context for initializer!");
4057+
TypeDC = TypeDC->getParent();
4058+
propertyInitializer = false;
4059+
}
4060+
assert(TypeDC->isTypeContext() && "Expected type decl context!");
4061+
4062+
if (TypeDC->getDeclaredTypeOfContext()->isEqual(baseType)) {
4063+
if (propertyInitializer)
4064+
TC.diagnose(UDE->getLoc(), diag::instance_member_in_initializer,
40194065
UDE->getName());
4020-
return true;
4066+
else
4067+
TC.diagnose(UDE->getLoc(),
4068+
diag::instance_member_in_default_parameter,
4069+
UDE->getName());
4070+
return true;
4071+
}
40214072
}
40224073

40234074
// Otherwise, complain about use of instance value on type.

test/NameBinding/name_lookup.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,16 @@ class Test19935319 {
485485
func getFoo() -> Int {}
486486
}
487487

488+
// <rdar://problem/27013358> Crash using instance member as default parameter
489+
class rdar27013358 {
490+
let defaultValue = 1
491+
func returnTwo() -> Int {
492+
return 2
493+
}
494+
init(defaulted value: Int = defaultValue) {} // expected-error {{cannot use instance member 'defaultValue' as a default parameter}}
495+
init(another value: Int = returnTwo()) {} // expected-error {{cannot use instance member 'returnTwo' as a default parameter}}
496+
}
497+
488498
// <rdar://problem/23904262> QoI: ivar default initializer cannot reference other default initialized ivars?
489499
class r23904262 {
490500
let x = 1

0 commit comments

Comments
 (0)