Skip to content

Commit a1bde15

Browse files
author
Josh Learn
committed
[diagnose-unreachable] Fix incorrect diagnostic on keypath creation
If the property referred to by the final component of a KeyPath is a type that is considered uninhabited by the compiler (e.g. caseless enums), we currently emit an unreachable code warning at the location of the KeyPath expression. This warning is emitted by the NoReturnFolding pass of the SILOptimizer when it checks the property getter function generated for the KeyPath. This change fixes the issue by emitting keypath accessor functions with artificial SILLocations so that the diagnostics pass will skip it as non-user-written code. rdar://80415811
1 parent ce660f5 commit a1bde15

File tree

3 files changed

+78
-7
lines changed

3 files changed

+78
-7
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2692,7 +2692,6 @@ getRepresentativeAccessorForKeyPath(AbstractStorageDecl *storage) {
26922692
}
26932693

26942694
static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM,
2695-
SILLocation loc,
26962695
AbstractStorageDecl *property,
26972696
SubstitutionMap subs,
26982697
GenericEnvironment *genericEnv,
@@ -2759,6 +2758,8 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM,
27592758
auto name = Mangle::ASTMangler()
27602759
.mangleKeyPathGetterThunkHelper(property, genericSig, baseType,
27612760
subs, expansion);
2761+
auto loc = RegularLocation::getAutoGeneratedLocation();
2762+
27622763
SILGenFunctionBuilder builder(SGM);
27632764
auto thunk = builder.getOrCreateSharedFunction(
27642765
loc, name, signature, IsBare, IsNotTransparent,
@@ -2806,7 +2807,6 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM,
28062807
auto baseSubstValue = emitKeyPathRValueBase(subSGF, property,
28072808
loc, baseArg,
28082809
baseType, subs);
2809-
28102810
auto subscriptIndices =
28112811
loadIndexValuesForKeyPathComponent(subSGF, loc, property,
28122812
indexes, indexPtrArg);
@@ -2832,7 +2832,6 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM,
28322832
}
28332833

28342834
static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM,
2835-
SILLocation loc,
28362835
AbstractStorageDecl *property,
28372836
SubstitutionMap subs,
28382837
GenericEnvironment *genericEnv,
@@ -2907,6 +2906,7 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM,
29072906
auto name = Mangle::ASTMangler()
29082907
.mangleKeyPathSetterThunkHelper(property, genericSig, baseType,
29092908
subs, expansion);
2909+
auto loc = RegularLocation::getAutoGeneratedLocation();
29102910

29112911
SILGenFunctionBuilder builder(SGM);
29122912
auto thunk = builder.getOrCreateSharedFunction(
@@ -3536,13 +3536,13 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
35363536
// expected by the key path runtime.
35373537
auto id = getIdForKeyPathComponentComputedProperty(*this, var,
35383538
strategy);
3539-
auto getter = getOrCreateKeyPathGetter(*this, loc,
3539+
auto getter = getOrCreateKeyPathGetter(*this,
35403540
var, subs,
35413541
needsGenericContext ? genericEnv : nullptr,
35423542
expansion, {}, baseTy, componentTy);
35433543

35443544
if (isSettableInComponent()) {
3545-
auto setter = getOrCreateKeyPathSetter(*this, loc,
3545+
auto setter = getOrCreateKeyPathSetter(*this,
35463546
var, subs,
35473547
needsGenericContext ? genericEnv : nullptr,
35483548
expansion, {}, baseTy, componentTy);
@@ -3587,7 +3587,7 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
35873587
}
35883588

35893589
auto id = getIdForKeyPathComponentComputedProperty(*this, decl, strategy);
3590-
auto getter = getOrCreateKeyPathGetter(*this, loc,
3590+
auto getter = getOrCreateKeyPathGetter(*this,
35913591
decl, subs,
35923592
needsGenericContext ? genericEnv : nullptr,
35933593
expansion,
@@ -3596,7 +3596,7 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
35963596

35973597
auto indexPatternsCopy = getASTContext().AllocateCopy(indexPatterns);
35983598
if (isSettableInComponent()) {
3599-
auto setter = getOrCreateKeyPathSetter(*this, loc,
3599+
auto setter = getOrCreateKeyPathSetter(*this,
36003600
decl, subs,
36013601
needsGenericContext ? genericEnv : nullptr,
36023602
expansion,

test/SILGen/sil_locations.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,3 +417,29 @@ func testWhile() {
417417

418418

419419
}
420+
421+
// Check that the sil location of keypath getter/setter functions is
422+
// marked as autogenerated.
423+
struct Struct {
424+
var structProperty: InnerStruct {
425+
get { InnerStruct() }
426+
set(newStruct) { }
427+
}
428+
429+
struct InnerStruct {}
430+
}
431+
432+
func testKeyPathGetterSetterAutogen() -> Struct.InnerStruct {
433+
let kp = \Struct.structProperty
434+
var s = Struct()
435+
let innerS = Struct.InnerStruct()
436+
437+
s[keyPath: kp] = innerS
438+
return s[keyPath: kp]
439+
// Autogenerated keypath getter
440+
// CHECK-LABEL: sil shared [thunk] [ossa] @$s13sil_locations6StructV14structProperty{{[_0-9a-zA-Z]*}}TK
441+
// CHECK: load {{.*}} loc "<compiler-generated>":0:0{{.*}}<invalid loc>:auto_gen
442+
// Autogenerated keypath setter
443+
// CHECK-LABEL: sil shared [thunk] [ossa] @$s13sil_locations6StructV14structProperty{{[_0-9a-zA-Z]*}}Tk
444+
// CHECK: load {{.*}} loc "<compiler-generated>":0:0{{.*}}<invalid loc>:auto_gen
445+
}

test/SILOptimizer/diagnose_unreachable.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,3 +470,48 @@ extension Collection {
470470
}
471471
}
472472

473+
// rdar://80415811
474+
// Incorrect unreachable code diagnostic for keypath to empty Enum caused by
475+
// the generated keypath getter function having an uninhabited return type.
476+
// The getter function was previously tied to the source location of the
477+
// corresponding keypath expression, which caused it to be diagnosed as
478+
// user code. The getter and setter functions now have an autogenerated
479+
// source location so we should not expect an unreachable code warning until
480+
// the keypath expression is actually used.
481+
struct StructWithNeverProp {
482+
var property: Never {
483+
fatalError()
484+
}
485+
}
486+
487+
func keypathToEmptyEnum() -> Never {
488+
// Check that the generated keypath getter function for this property
489+
// does not trigger an unreachable code warning here.
490+
let kp = \StructWithNeverProp.property // no warning
491+
let s = StructWithNeverProp()
492+
// Emit a diagnostic here becase the keypath is actually used.
493+
let prop = s[keyPath: kp]
494+
// expected-warning@-1 {{will never be executed}} \
495+
// expected-note {{a call to a never-returning function}} \
496+
// expected-warning {{constant 'prop' inferred to have type 'Never', which is an enum with no cases}} \
497+
// expected-note {{add an explicit type annotation to silence this warning}}
498+
return prop
499+
}
500+
501+
struct OuterStruct {
502+
public let innerEnum: InnerEnum
503+
public enum InnerEnum { }
504+
}
505+
506+
@dynamicMemberLookup
507+
public enum DynamicLookupEnum {
508+
subscript<T>(dynamicMember keyPath: KeyPath<OuterStruct, T>) -> T {
509+
fatalError()
510+
}
511+
}
512+
513+
func keypathWithDynamicLookup() {
514+
// Check that we still don't diagnose the keypath getter as unreachable
515+
// when used in conjuction with a dynamicMemberLookup enum.
516+
let _ = \DynamicLookupEnum.innerEnum // no warning
517+
}

0 commit comments

Comments
 (0)