Skip to content

Commit ee6c0a7

Browse files
committed
Fix crash when using instance member as default parameter.
Also produce a specific diagnostic for this case. rdar://problem/27013358
1 parent 932fe9d commit ee6c0a7

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

23202350
diagnose(loc, diag::could_not_use_instance_member_on_type,
@@ -3963,18 +3993,39 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
39633993
auto DC = CCI.CS->DC;
39643994

39653995
// If the base is an implicit self type reference, and we're in a
3966-
// property initializer, then the user wrote something like:
3996+
// an initializer, then the user wrote something like:
39673997
//
39683998
// class Foo { let val = initFn() }
3999+
// or
4000+
// class Bar { func something(x: Int = initFn()) }
39694001
//
39704002
// which runs in type context, not instance context. Produce a tailored
39714003
// diagnostic since this comes up and is otherwise non-obvious what is
39724004
// going on.
3973-
if (UDE->getBase()->isImplicit() && isa<Initializer>(DC) &&
3974-
DC->getParent()->getDeclaredTypeOfContext()->isEqual(baseType)){
3975-
TC.diagnose(UDE->getLoc(), diag::instance_member_in_initializer,
4005+
if (UDE->getBase()->isImplicit() && isa<Initializer>(DC)) {
4006+
auto *TypeDC = DC->getParent();
4007+
bool propertyInitializer = true;
4008+
// If the parent context is not a type context, we expect it
4009+
// to be a defaulted parameter in a function declaration.
4010+
if (!TypeDC->isTypeContext()) {
4011+
assert(TypeDC->getContextKind() ==
4012+
DeclContextKind::AbstractFunctionDecl &&
4013+
"Expected function decl context for initializer!");
4014+
TypeDC = TypeDC->getParent();
4015+
propertyInitializer = false;
4016+
}
4017+
assert(TypeDC->isTypeContext() && "Expected type decl context!");
4018+
4019+
if (TypeDC->getDeclaredTypeOfContext()->isEqual(baseType)) {
4020+
if (propertyInitializer)
4021+
TC.diagnose(UDE->getLoc(), diag::instance_member_in_initializer,
39764022
UDE->getName());
3977-
return true;
4023+
else
4024+
TC.diagnose(UDE->getLoc(),
4025+
diag::instance_member_in_default_parameter,
4026+
UDE->getName());
4027+
return true;
4028+
}
39784029
}
39794030

39804031
// 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)