Skip to content

Commit d118654

Browse files
committed
Sema: Peephole for 'nil' literal of Optional type
1 parent fb499ca commit d118654

10 files changed

+79
-42
lines changed

lib/Sema/CSApply.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,41 @@ namespace {
19651965
type = defaultType;
19661966
}
19671967

1968+
// By far the most common 'nil' literal is for Optional<T>.none.
1969+
//
1970+
// Emit this case directly instead of calling Optional.init(nilLiteral:),
1971+
// since this generates more efficient SIL.
1972+
if (auto objectType = type->getOptionalObjectType()) {
1973+
auto *nilDecl = tc.Context.getOptionalNoneDecl();
1974+
tc.validateDecl(nilDecl);
1975+
if (!nilDecl->hasInterfaceType())
1976+
return nullptr;
1977+
1978+
SubstitutionList subs = {Substitution(objectType, {})};
1979+
ConcreteDeclRef concreteDeclRef(tc.Context, nilDecl, subs);
1980+
1981+
auto nilType = FunctionType::get(
1982+
{MetatypeType::get(type)}, type);
1983+
auto *nilRefExpr = new (tc.Context) DeclRefExpr(
1984+
concreteDeclRef, DeclNameLoc(expr->getLoc()),
1985+
/*implicit=*/true, AccessSemantics::Ordinary,
1986+
nilType);
1987+
cs.cacheType(nilRefExpr);
1988+
1989+
auto *typeExpr = TypeExpr::createImplicitHack(
1990+
expr->getLoc(),
1991+
type,
1992+
tc.Context);
1993+
cs.cacheType(typeExpr);
1994+
1995+
auto *callExpr = new (tc.Context) DotSyntaxCallExpr(
1996+
nilRefExpr, expr->getLoc(), typeExpr, type);
1997+
callExpr->setImplicit(true);
1998+
cs.cacheType(callExpr);
1999+
2000+
return callExpr;
2001+
}
2002+
19682003
DeclName initName(tc.Context, DeclBaseName::createConstructor(),
19692004
{ tc.Context.Id_nilLiteral });
19702005
return convertLiteral(expr, type, cs.getType(expr), protocol,

lib/Sema/MiscDiagnostics.cpp

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,27 +1423,42 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
14231423

14241424
}
14251425

1426-
/// Return true if this is 'nil' type checked as an Optional. This looks
1427-
/// like this:
1428-
/// (call_expr implicit type='Int?'
1429-
/// (constructor_ref_call_expr implicit
1430-
/// (declref_expr implicit decl=Optional.init(nilLiteral:)
1431-
static bool isTypeCheckedOptionalNil(Expr *E) {
1432-
auto CE = dyn_cast<CallExpr>(E->getSemanticsProvidingExpr());
1426+
/// Return true if this is a 'nil' literal. This looks
1427+
/// like this if the type is Optional<T>:
1428+
///
1429+
/// (dot_syntax_call_expr implicit type='Int?'
1430+
/// (declref_expr implicit decl=Optional.none)
1431+
/// (type_expr type=Int?))
1432+
///
1433+
/// Or like this if it is any other ExpressibleByNilLiteral type:
1434+
///
1435+
/// (dot_syntax_call_expr implicit type='Int?'
1436+
/// (declref_expr implicit decl=Optional.none)
1437+
/// (type_expr type=Int?))
1438+
///
1439+
bool isTypeCheckedOptionalNil(Expr *E) {
1440+
auto CE = dyn_cast<ApplyExpr>(E->getSemanticsProvidingExpr());
14331441
if (!CE || !CE->isImplicit())
14341442
return false;
1435-
1443+
1444+
// First case -- Optional.none
1445+
if (auto DRE = dyn_cast<DeclRefExpr>(CE->getSemanticFn()))
1446+
return DRE->getDecl() == TC.Context.getOptionalNoneDecl();
1447+
1448+
// Second case -- init(nilLiteral:)
14361449
auto CRCE = dyn_cast<ConstructorRefCallExpr>(CE->getSemanticFn());
14371450
if (!CRCE || !CRCE->isImplicit()) return false;
1438-
1439-
auto DRE = dyn_cast<DeclRefExpr>(CRCE->getSemanticFn());
1440-
1441-
SmallString<32> NameBuffer;
1442-
auto name = DRE->getDecl()->getFullName().getString(NameBuffer);
1443-
return name == "init(nilLiteral:)";
1451+
1452+
if (auto DRE = dyn_cast<DeclRefExpr>(CRCE->getSemanticFn())) {
1453+
SmallString<32> NameBuffer;
1454+
auto name = DRE->getDecl()->getFullName().getString(NameBuffer);
1455+
return name == "init(nilLiteral:)";
1456+
}
1457+
1458+
return false;
14441459
}
1445-
1446-
1460+
1461+
14471462
/// Warn about surprising implicit optional promotions involving operands to
14481463
/// calls. Specifically, we warn about these expressions when the 'x'
14491464
/// operand is implicitly promoted to optional:

test/IRGen/big_types_corner_cases.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ public func enumCallee(_ x: LargeEnum) {
151151
// CHECK-64: [[ALLOC1:%.*]] = alloca %T22big_types_corner_cases9BigStructV
152152
// CHECK-64: [[ALLOC2:%.*]] = alloca %T22big_types_corner_cases9BigStructV
153153
// CHECK-64: [[ALLOC3:%.*]] = alloca %T22big_types_corner_cases9BigStructVSg
154-
// CHECK-64: [[ALLOC4:%.*]] = alloca %T22big_types_corner_cases9BigStructVSg
155154
// CHECK-64: call swiftcc void @"$S22big_types_corner_cases9SuperBaseC4boomAA9BigStructVyF"(%T22big_types_corner_cases9BigStructV* noalias nocapture sret [[ALLOC1]], %T22big_types_corner_cases9SuperBaseC* swiftself {{.*}})
156155
// CHECK: ret void
157156
class SuperBase {

test/IRGen/class_bounded_generics.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,8 @@ class M<T, S: A<T>> {
282282
// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics14takes_metatypeyyxmlF"(%swift.type*, %swift.type* %T)
283283
func takes_metatype<T>(_: T.Type) {}
284284

285-
// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.2*, %swift.type* %T)
286-
// CHECK: [[ISA_ADDR:%.*]] = bitcast %T22class_bounded_generics1AC.2* %0 to %swift.type**
285+
// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.1*, %swift.type* %T)
286+
// CHECK: [[ISA_ADDR:%.*]] = bitcast %T22class_bounded_generics1AC.1* %0 to %swift.type**
287287
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
288288
// CHECK-NEXT: call swiftcc void @"$S22class_bounded_generics14takes_metatypeyyxmlF"(%swift.type* %T, %swift.type* %T)
289289
// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
@@ -300,12 +300,12 @@ func archetype_with_generic_class_constraint<T, U>(t: T) where T : A<U> {
300300
// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics029calls_archetype_with_generic_A11_constraint1ayAA1ACyxG_tlF"(%T22class_bounded_generics1AC*) #0 {
301301
// CHECK: [[ISA_ADDR:%.*]] = getelementptr inbounds %T22class_bounded_generics1AC, %T22class_bounded_generics1AC* %0, i32 0, i32 0, i32 0
302302
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
303-
// CHECK: [[SELF:%.*]] = bitcast %T22class_bounded_generics1AC* %0 to %T22class_bounded_generics1AC.2*
303+
// CHECK: [[SELF:%.*]] = bitcast %T22class_bounded_generics1AC* %0 to %T22class_bounded_generics1AC.1*
304304
// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
305305
// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ISA_PTR]], i64 10
306306
// CHECK-NEXT: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]]
307307
// CHECK-NEXT: [[A_OF_T:%.*]] = call %swift.type* @"$S22class_bounded_generics1ACMa"(%swift.type* [[T]])
308-
// CHECK-NEXT: call swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.2* [[SELF]], %swift.type* [[A_OF_T]])
308+
// CHECK-NEXT: call swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.1* [[SELF]], %swift.type* [[A_OF_T]])
309309
// CHECK: ret void
310310

311311
func calls_archetype_with_generic_class_constraint<T>(a: A<T>) {

test/IRGen/class_resilience_thunks.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ public func testDispatchThunkDerived(d: Derived) {
2929
// CHECK: call swiftcc void @"$S22resilient_class_thunks4BaseC6takesTyyxFTj"(%swift.opaque* noalias nocapture dereferenceable({{4|8}}) {{%.*}}, %T22resilient_class_thunks4BaseC* swiftself {{%.*}})
3030
d.takesT(0)
3131

32-
// CHECK: call swiftcc void @"$S22resilient_class_thunks7DerivedC8takesIntyySiSgFTj"([[INT]] {{%.*}}, i8 {{%.*}}, %T22resilient_class_thunks7DerivedC* swiftself %0)
32+
// CHECK: call swiftcc void @"$S22resilient_class_thunks7DerivedC8takesIntyySiSgFTj"([[INT]] 0, i8 1, %T22resilient_class_thunks7DerivedC* swiftself %0)
3333
d.takesInt(nil)
3434

35-
// CHECK: call swiftcc void @"$S22resilient_class_thunks4BaseC14takesReferenceyyAA6ObjectCFTj"(%T22resilient_class_thunks6ObjectC* {{%.*}}, %T22resilient_class_thunks4BaseC* swiftself {{%.*}})
35+
// CHECK: call swiftcc void @"$S22resilient_class_thunks4BaseC14takesReferenceyyAA6ObjectCFTj"(%T22resilient_class_thunks6ObjectC* null, %T22resilient_class_thunks4BaseC* swiftself {{%.*}})
3636
d.takesReference(nil)
3737

3838
// CHECK: ret void

test/IRGen/dynamic_self_metadata.swift

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,11 @@
1515
class C {
1616
class func fromMetatype() -> Self? { return nil }
1717
// CHECK-LABEL: define hidden swiftcc i64 @"$S21dynamic_self_metadata1CC12fromMetatypeACXDSgyFZ"(%swift.type* swiftself)
18-
// CHECK: [[ALLOCA:%.+]] = alloca [[TYPE]], align 8
19-
// CHECK: [[CAST1:%.+]] = bitcast [[TYPE]]* [[ALLOCA]] to i64*
20-
// CHECK: store i64 0, i64* [[CAST1]], align 8
21-
// CHECK: [[CAST2:%.+]] = bitcast [[TYPE]]* [[ALLOCA]] to i64*
22-
// CHECK: [[LOAD:%.+]] = load i64, i64* [[CAST2]], align 8
23-
// CHECK: ret i64 [[LOAD]]
18+
// CHECK: ret i64 0
2419

2520
func fromInstance() -> Self? { return nil }
2621
// CHECK-LABEL: define hidden swiftcc i64 @"$S21dynamic_self_metadata1CC12fromInstanceACXDSgyF"(%T21dynamic_self_metadata1CC* swiftself)
27-
// CHECK: [[ALLOCA:%.+]] = alloca [[TYPE]], align 8
28-
// CHECK: [[CAST1:%.+]] = bitcast [[TYPE]]* [[ALLOCA]] to i64*
29-
// CHECK: store i64 0, i64* [[CAST1]], align 8
30-
// CHECK: [[CAST2:%.+]] = bitcast [[TYPE]]* [[ALLOCA]] to i64*
31-
// CHECK: [[LOAD:%.+]] = load i64, i64* [[CAST2]], align 8
32-
// CHECK: ret i64 [[LOAD]]
22+
// CHECK: ret i64 0
3323

3424
func dynamicSelfArgument() -> Self? {
3525
return id(nil)

test/SILGen/access_marker_gen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func takeS(_ s: S) {}
4848
// CHECK: %[[BOX:.*]] = alloc_box ${ var S }, var, name "s"
4949
// CHECK: %[[ADDRS:.*]] = project_box %[[BOX]] : ${ var S }, 0
5050
// CHECK: %[[ACCESS1:.*]] = begin_access [modify] [unknown] %[[ADDRS]] : $*S
51-
// CHECK: %[[ADDRI:.*]] = struct_element_addr %15 : $*S, #S.i
51+
// CHECK: %[[ADDRI:.*]] = struct_element_addr %[[ACCESS1]] : $*S, #S.i
5252
// CHECK: assign %{{.*}} to %[[ADDRI]] : $*Int
5353
// CHECK: end_access %[[ACCESS1]] : $*S
5454
// CHECK: %[[ACCESS2:.*]] = begin_access [read] [unknown] %[[ADDRS]] : $*S

test/SILGen/default_arguments_imported.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import gizmo
88

99
// CHECK-LABEL: sil hidden @$S26default_arguments_imported9testGizmo{{[_0-9a-zA-Z]*}}F
1010
func testGizmo(gizmo: Gizmo) {
11-
// CHECK: function_ref @$SSq10nilLiteralxSgyt_tcfC
11+
// CHECK: enum $Optional<@callee_guaranteed (@owned Optional<Gizmo>) -> ()>, #Optional.none!enumelt
1212
// CHECK: objc_method [[SELF:%[0-9]+]] : $Gizmo, #Gizmo.enumerateSubGizmos!1.foreign
1313
gizmo.enumerateSubGizmos()
1414
} // CHECK: } // end sil function '$S26default_arguments_imported9testGizmo5gizmoySo0E0C_tF'
@@ -24,7 +24,7 @@ func testNonnullDictionary(gizmo: Gizmo) {
2424
// CHECK-LABEL: sil hidden @$S26default_arguments_imported22testNullableDictionary5gizmoySo5GizmoC_tF
2525
func testNullableDictionary(gizmo: Gizmo) {
2626
// CHECK-NOT: dictionaryLiteral
27-
// CHECK: function_ref @$SSq10nilLiteralxSgyt_tcfC
27+
// CHECK: enum $Optional<Dictionary<AnyHashable, Any>>, #Optional.none!enumelt
2828
// CHECK: objc_method [[SELF:%[0-9]+]] : $Gizmo, #Gizmo.doTheOtherThing!1.foreign
2929
gizmo.doTheOtherThing()
3030
} // CHECK: } // end sil function '$S26default_arguments_imported22testNullableDictionary5gizmoySo5GizmoC_tF'

test/SILGen/extensions.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ func extensionMethodCurrying(_ x: Foo) {
4545
// CHECK-LABEL: sil hidden [transparent] @$S10extensions3BoxV1txSgvpfi : $@convention(thin) <T> () -> @out Optional<T>
4646
// CHECK: bb0(%0 : @trivial $*Optional<T>):
4747
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin Optional<T>.Type
48-
// CHECK: [[FN:%.*]] = function_ref @$SSq10nilLiteralxSgyt_tcfC : $@convention(method) <τ_0_0> (@thin Optional<τ_0_0>.Type) -> @out Optional<τ_0_0>
49-
// CHECK-NEXT: apply [[FN]]<T>(%0, [[METATYPE]]) : $@convention(method) <τ_0_0> (@thin Optional<τ_0_0>.Type) -> @out Optional<τ_0_0>
48+
// CHECK: inject_enum_addr %0 : $*Optional<T>, #Optional.none!enumelt
5049
// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
5150
// CHECK-NEXT: return [[RESULT]] : $()
5251

test/SILGen/objc_imported_generic.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,7 @@ func genericFunc<V: AnyObject>(_ v: V.Type) {
120120
}
121121

122122
// CHECK-LABEL: sil hidden @$S21objc_imported_generic23configureWithoutOptionsyyF : $@convention(thin) () -> ()
123-
// CHECK: [[NIL_FN:%.*]] = function_ref @$SSq10nilLiteralxSgyt_tcfC : $@convention(method) <τ_0_0> (@thin Optional<τ_0_0>.Type) -> @out Optional<τ_0_0>
124-
// CHECK: apply [[NIL_FN]]<[GenericOption : Any]>({{.*}})
123+
// CHECK: enum $Optional<Dictionary<GenericOption, Any>>, #Optional.none!enumelt
125124
// CHECK: return
126125
func configureWithoutOptions() {
127126
_ = GenericClass<NSObject>(options: nil)

0 commit comments

Comments
 (0)