SwiftやSwiftUIでEnum Case、Static Member、OptionSetなどを先頭のドットを使って省略記法で指定したとき、Xcodeに次のようなErrorが表示されることがあります。
Cannot infer contextual base in reference to member 'center'
ほかにも:
Cannot infer contextual base in reference to member 'horizontal'
や:
Cannot infer contextual base in reference to member 'red'
など、末尾のMember名だけが変わったDiagnosticが表示されます。
このErrorは、.centerや.redのような省略記法を使っているものの、Swift Compilerが「どのTypeのcenterなのか」「どのTypeのredなのか」をContextから判断できない場合に発生します。
基本的な解決方法は、対象のTypeを明示する、VariableやParameterにType Annotationを付ける、または周囲の別のType Errorを先に修正することです。
- 「Cannot infer contextual base」とは
- 代表的な発生状況
- 主な原因
- 1. Enum Caseだけを書いている
- 2. Function ArgumentのExpected Typeが決まらない
- 3. SwiftUIのAlignmentでTypeが曖昧
- 4. ColorやShapeStyleのContextが不足している
- 5. OptionSetのTypeが不明
- 6. 空Arrayと省略Memberを組み合わせている
- 7. Generic Function内でType情報が不足している
- 8. ClosureのParameter Typeが不明
- 9. Optional Contextが不足している
- 10. 三項演算子の両Branchが曖昧
- 11. Function ReferenceやOverloadが多い
- 12. SwiftUI Modifierの別ArgumentにErrorがある
- 13. BindingとValueが間違っている
- 14. OptionalとNon-Optionalが一致していない
- 15. SDKやPackage UpdateでAPI Signatureが変わった
- まず確認すること
- 解決方法1:Enum Typeを明示する
- 解決方法2:Static MemberのType名を書く
- 解決方法3:Alignmentの種類を明示する
- 解決方法4:SwiftUI Modifier内で完全なType名を使う
- 解決方法5:ArrayへElement Typeを付ける
- 解決方法6:DictionaryのValue Typeを明示する
- 解決方法7:ClosureのResult Typeを明示する
- 解決方法8:Closure Return Typeを直接書く
- 解決方法9:三項演算子のResult Typeを付ける
- 解決方法10:Optional Typeを明示する
- 解決方法11:Function Parameter Typeを確認する
- 解決方法12:Overloadを明示的に区別する
- 解決方法13:Generic Result Typeを明示する
- 解決方法14:OptionSetのTypeを明示する
- 解決方法15:SwiftUIのColorを明示する
- 解決方法16:SwiftUIのAxisを明示する
- 解決方法17:SwiftUIのTextAlignmentを明示する
- 解決方法18:Binding Errorを先に直す
- 解決方法19:Optionalを先にUnwrapする
- 解決方法20:Generic FunctionへConcrete Type情報を与える
- 解決方法21:Function ReferenceのTypeを明示する
- 解決方法22:複雑なExpressionを分割する
- 解決方法23:SwiftUIのCustom View Argument Typeを確認する
- 解決方法24:SwiftUIのModifierを一度分割する
- 解決方法25:同じ名前のTypeをModule名で区別する
- 解決方法26:古いAPI Sampleを現在のSignatureへ合わせる
- 解決方法27:Cannot infer contextual baseより前のErrorを修正する
- 解決方法28:Autocompleteで完全なMember名を確認する
- 解決方法29:TypealiasやGeneric Aliasを確認する
- 解決方法30:省略記法を使わず完全修飾名で切り分ける
- SwiftUIでよくある例
- Enumで発生する場合
- mapで発生する場合
- switchで発生する場合
- Resultで発生する場合
- 「Typeを明示しても直らない」場合
- Clean Build Folderで直るか
- DerivedData削除は必要か
- やってはいけない対処
- 最短で確認するチェックリスト
- まとめ
「Cannot infer contextual base」とは
Swiftでは、Expected Typeが分かっている場合にEnum CaseやStatic MemberのType名を省略できます。
例えば:
enum Direction { case left case right }
let direction: Direction = .left
directionのTypeがDirectionだと分かっているため、Compilerは:
.left
を:
Direction.left
として解釈できます。
ところが:
let direction = .left
だけでは、.leftがどのTypeに属しているのか判断できません。
そのため、Contextによっては:
Cannot infer contextual base in reference to member 'left'
のようなErrorになります。
ポイント:「contextual base」とは、簡単に言えば「このMemberが属しているはずのType」です。CompilerがそのTypeをContextから推論できないと、このErrorが発生します。
代表的な発生状況
- Enum Caseを
.caseNameだけで代入した - VariableのType Annotationがない
- Generic Functionへ省略形のEnum Caseを渡した
- SwiftUI ModifierでExpected Typeを特定できない
- Color、Alignment、AxisなどのStatic Memberを省略している
- OptionSetのMemberをContextなしで使用した
- OptionalやGenericのTypeが曖昧になっている
- Function Overloadが複数ありParameter Typeを決められない
- Closure内部でType情報が失われている
- 前のCompiler ErrorによってExpected Typeを推論できなくなっている
主な原因
1. Enum Caseだけを書いている
問題:
let direction = .left
Compilerには.leftがどのEnumのCaseなのか分かりません。
修正:
let direction: Direction = .left
または:
let direction = Direction.left
2. Function ArgumentのExpected Typeが決まらない
例えば複数のOverloadがある場合です。
func configure( alignment: HorizontalAlignment ) { }
func configure(
alignment: VerticalAlignment
) {
}
次のようなCallでは、Member名によってはどちらを使うべきか判断できないことがあります。
configure( alignment: .center )
HorizontalAlignment.centerとVerticalAlignment.centerの両方がCandidateになるためです。
3. SwiftUIのAlignmentでTypeが曖昧
SwiftUIには:
- Alignment
- HorizontalAlignment
- VerticalAlignment
など、似たMemberを持つTypeがあります。
.centerだけでは、周囲のAPIが曖昧な場合にTypeを推論できないことがあります。
4. ColorやShapeStyleのContextが不足している
例えば:
let color = .red
だけでは、CompilerがどのTypeのredなのか判断できないことがあります。
修正:
let color: Color = .red
または:
let color = Color.red
5. OptionSetのTypeが不明
例えば:
let options = [.allowAirPlay, .mixWithOthers]
Contextがない場合、どのOptionSetのMemberなのかCompilerが判断できないことがあります。
6. 空Arrayと省略Memberを組み合わせている
let values = [.one, .two]
Element Typeを推論できない場合、それぞれのMemberのBase Typeも分かりません。
7. Generic Function内でType情報が不足している
Generic ParameterのConcrete Typeが確定していないと、Static MemberやEnum Caseを省略した記述が成立しない場合があります。
8. ClosureのParameter Typeが不明
items.map { item in .selected }
Result Typeが決まっていない場合、.selectedのTypeも推論できません。
9. Optional Contextが不足している
例えば:
let state = condition ? .active : nil
Expected Optional Typeがないと、.activeのBase Typeを決められない場合があります。
10. 三項演算子の両Branchが曖昧
let alignment = isHorizontal ? .leading : .trailing
Variable Typeがない場合、Memberの所属Typeを決められないことがあります。
11. Function ReferenceやOverloadが多い
Call SiteでExpected Parameter Typeを1つへ絞れないと、引数の省略Memberも推論できません。
12. SwiftUI Modifierの別ArgumentにErrorがある
例えばModifierの別Parameterが不正なためにInitializerやMethod Candidateを選べず、その結果として.centerなどへ「Cannot infer contextual base」が表示されることがあります。
13. BindingとValueが間違っている
SwiftUIで正しいInitializerを選べないと、そのInitializerに依存していたEnumやStatic MemberのExpected Typeも失われます。
14. OptionalとNon-Optionalが一致していない
本来のOverloadがCandidateから外れ、結果的に省略MemberのTypeが推論できなくなることがあります。
15. SDKやPackage UpdateでAPI Signatureが変わった
以前はExpected Typeが明確だったParameterが削除・変更されると、古いCodeの省略Memberだけが残り、このErrorが出る場合があります。
まず確認すること
1. ErrorになっているMemberを完全なType名で書く
例えば:
.center
でErrorなら、意図しているTypeを確認して:
Alignment.center
または:
HorizontalAlignment.center
などにします。
これで直るなら、原因はContext不足です。
2. VariableにType Annotationを付ける
let alignment: HorizontalAlignment = .center
Expected Typeが確定します。
3. Errorの1行前や別Argumentを確認する
Compilerが本来使うべきFunctionやInitializerを特定できていない可能性があります。
重要:「Cannot infer contextual base」が表示されたMember自体が間違っているとは限りません。別のArgument Type、Argument Label、Bindingなどが原因でContextが失われていることがあります。
解決方法1:Enum Typeを明示する
修正前:
let state = .active
修正後:
let state: UserState = .active
または:
let state = UserState.active
解決方法2:Static MemberのType名を書く
SwiftUIで:
let color = Color.red
のようにBase Typeを直接書きます。
解決方法3:Alignmentの種類を明示する
例えば:
let alignment: HorizontalAlignment = .center
または:
let alignment = HorizontalAlignment.center
解決方法4:SwiftUI Modifier内で完全なType名を使う
例えば意図したTypeがAlignmentなら:
.frame( maxWidth: .infinity, alignment: Alignment.center )
と書くことで曖昧さを取り除けます。
解決方法5:ArrayへElement Typeを付ける
問題:
let states = [ .active, .inactive ]
修正:
let states: [UserState] = [ .active, .inactive ]
解決方法6:DictionaryのValue Typeを明示する
let states: [String: UserState] = [ "user1": .active, "user2": .inactive ]
解決方法7:ClosureのResult Typeを明示する
例えば:
let states: [UserState] = users.map { user in user.isActive ? .active : .inactive }
Result ArrayのTypeを指定すると、各Enum CaseのBase Typeが確定します。
解決方法8:Closure Return Typeを直接書く
let states = users.map { (user: User) -> UserState in
user.isActive
? .active
: .inactive
}
解決方法9:三項演算子のResult Typeを付ける
let alignment: HorizontalAlignment = isCentered ? .center : .leading
解決方法10:Optional Typeを明示する
let state: UserState? = condition ? .active : nil
これで.activeがUserStateであることをCompilerが判断できます。
解決方法11:Function Parameter Typeを確認する
例えば:
func setState( _ state: UserState ) { }
なら:
setState(.active)
で問題ありません。
ここでErrorになる場合、別Overloadや別ErrorによってExpected Typeを決められていない可能性があります。
解決方法12:Overloadを明示的に区別する
例えば:
func configure( alignment: HorizontalAlignment ) { }
func configure(
alignment: VerticalAlignment
) {
}
のように同名Overloadがあり、Member名も重なるなら:
configure( alignment: HorizontalAlignment.center )
とします。
解決方法13:Generic Result Typeを明示する
let value: Result<User, AppError> = .success(user)
.successがどのResult Typeなのか明確になります。
解決方法14:OptionSetのTypeを明示する
例えば:
let options: AVAudioSession.CategoryOptions = [ .mixWithOthers, .allowAirPlay ]
のようにOptionSet Typeを指定すると、各MemberのBaseが確定します。
解決方法15:SwiftUIのColorを明示する
let backgroundColor: Color = .red
または:
let backgroundColor = Color.red
解決方法16:SwiftUIのAxisを明示する
例えば:
let axis: Axis = .horizontal
複数選択のOptionSetならAPIが要求する具体的なTypeを確認してください。
解決方法17:SwiftUIのTextAlignmentを明示する
let alignment: TextAlignment = .center
HorizontalAlignment.centerやAlignment.centerとは別Typeなので、用途に対応したTypeを選びます。
解決方法18:Binding Errorを先に直す
例えば:
@State private var text = ""
TextField(
"Name",
text: $text
)
Bindingを要求するParameterへ通常のStringを渡していると、Initializer候補自体を決められず、周辺MemberにContext Errorが出ることがあります。
解決方法19:Optionalを先にUnwrapする
if let user { UserView( user: user ) }
OptionalによってOverload選択が複雑になっている場合、Concrete Typeへしてから渡します。
解決方法20:Generic FunctionへConcrete Type情報を与える
例えば:
let result: Result<User, AppError> = makeResult()
Return TypeからGeneric Parameterを確定させます。
解決方法21:Function ReferenceのTypeを明示する
let handler: (UserState) -> Void = setState
OverloadされたFunction Referenceを使う場合にもType Contextを与えると解決しやすくなります。
解決方法22:複雑なExpressionを分割する
例えば:
let state = users .filter { $0.isActive } .first .map { _ in .active }
でType推論が難しい場合:
let activeUser: User? = users.first { $0.isActive }
let state: UserState? =
activeUser.map { _ in
.active
}
のようにType Boundaryを作ります。
解決方法23:SwiftUIのCustom View Argument Typeを確認する
例えば:
struct StatusView: View { let state: UserState
var body: some View {
Text(state.title)
}
}
Call Site:
StatusView( state: .active )
ならExpected TypeがUserStateなので、省略Caseを利用できます。
これでErrorになる場合はCustom Initializerや別Argumentも確認してください。
解決方法24:SwiftUIのModifierを一度分割する
長いModifier Chainで発生する場合、問題部分をVariableやSub Viewに分けます。
let alignment: Alignment = .center
Text("Hello")
.frame(
maxWidth: .infinity,
alignment: alignment
)
解決方法25:同じ名前のTypeをModule名で区別する
複数Moduleに同名Typeがある場合:
FrameworkA.Status.active
のようにModuleまで明示するとContextを限定できます。
解決方法26:古いAPI Sampleを現在のSignatureへ合わせる
SDKやPackage Update後にErrorが発生した場合は、XcodeのAutocompleteやJump to Definitionで現在のParameter Typeを確認してください。
以前のAPIでは:
alignment: .center
で利用できていても、現在は別TypeのParameterになっている可能性があります。
解決方法27:Cannot infer contextual baseより前のErrorを修正する
同じExpression内に:
Cannot convert value of type ... Ambiguous use of ... Missing argument for parameter ... Generic parameter could not be inferred
などがある場合は、それらを先に修正してください。
Expected Typeが復元されると、「Cannot infer contextual base」も消えることがあります。
解決方法28:Autocompleteで完全なMember名を確認する
例えば.centerを使いたい箇所で、一度:
HorizontalAlignment.
や:
Alignment.
まで入力してAutocomplete候補を確認します。
これにより、自分が想定しているTypeにそのMemberが本当に存在するか確認できます。
解決方法29:TypealiasやGeneric Aliasを確認する
複雑なTypealiasによって実際のExpected Typeが分かりにくい場合があります。
一時的にConcrete Typeへ展開すると原因を特定しやすくなります。
解決方法30:省略記法を使わず完全修飾名で切り分ける
原因が分からない場合は、一度すべてのDot Syntaxを完全なType名へ置き換えます。
例えば:
let state = UserState.active
let alignment =
HorizontalAlignment.center
let color =
Color.red
これでCompileできれば、Type Context不足が原因だったと判断できます。
SwiftUIでよくある例
frameのalignment
正しい例:
Text("Hello") .frame( maxWidth: .infinity, alignment: .center )
通常はframeのParameter Typeから.centerを推論できます。
しかし別ArgumentにErrorがある場合などは:
Text("Hello") .frame( maxWidth: .infinity, alignment: Alignment.center )
と完全なTypeを明示して切り分けます。
multilineTextAlignment
Text("Hello") .multilineTextAlignment( .center )
ここで要求されるのはTextAlignmentです。
明示するなら:
Text("Hello") .multilineTextAlignment( TextAlignment.center )
HStackのalignment
HStack( alignment: .center ) { Text("A") Text("B") }
HStackのalignmentはVerticalAlignmentです。
明示するなら:
HStack( alignment: VerticalAlignment.center ) { Text("A") Text("B") }
VStackのalignment
VStack( alignment: .leading ) { Text("A") Text("B") }
VStackのalignmentはHorizontalAlignmentです。
明示するなら:
VStack( alignment: HorizontalAlignment.leading ) { Text("A") Text("B") }
注意:SwiftUIには似た名前のAlignment Typeが複数あります。.centerだけを見て判断せず、そのAPIが要求する具体的なTypeを確認してください。
Enumで発生する場合
例えば:
enum LoadingState { case idle case loading case completed }
これはErrorになり得ます。
let state = .loading
修正:
let state: LoadingState = .loading
または:
let state = LoadingState.loading
mapで発生する場合
問題:
let states = users.map { user in user.isActive ? .active : .inactive }
修正:
let states: [UserState] = users.map { user in user.isActive ? .active : .inactive }
switchで発生する場合
通常、switch対象のTypeが分かっていればCaseを省略記法で書けます。
switch state { case .active: print("Active")
case .inactive:
print("Inactive")
}
もしCase側でContext Errorが出るなら、state自体のTypeが正しく確定しているか確認してください。
Resultで発生する場合
問題:
let result = .success(user)
ではFailure Typeが分からない場合があります。
修正:
let result: Result<User, AppError> = .success(user)
「Typeを明示しても直らない」場合
その場合は次を確認してください。
- 指定したTypeにそのMemberが本当に存在するか
- Argument Labelが正しいか
- 別ArgumentのTypeが正しいか
- Overload Candidateが複数ないか
- OptionalとNon-Optionalが一致しているか
- SwiftUIでBindingとValueを間違えていないか
- Generic Parameterが推論できているか
- 古いAPI Signatureを使っていないか
Clean Build Folderで直るか
通常は直りません。
このErrorは、Source Codeから必要なType Contextを得られないことが主な原因です。
補助的に:
Product → Clean Build Folder
を実行できますが、.centerや.activeのBase Typeが不明なままなら再びErrorになります。
DerivedData削除は必要か
IndexやBuild Cacheが不自然な場合は:
rm -rf ~/Library/Developer/Xcode/DerivedData/*
を補助的に試すことはできます。
ただし、本質的な解決方法はTypeを明示するか、周囲のType Errorを修正することです。
注意:このErrorでは、DerivedData削除を繰り返すより、Expected TypeをCompilerが判断できるCodeになっているか確認してください。
やってはいけない対処
Errorを消すためだけに、意図を確認せず適当なTypeへCastするのは避けてください。
例えば.centerには、Contextによって:
- Alignment.center
- HorizontalAlignment.center
- VerticalAlignment.center
- TextAlignment.center
など異なる意味があります。
どのAPIへ渡す値なのか確認してから、正しいTypeを指定してください。
最短で確認するチェックリスト
- Errorになっている省略Memberの完全なType名を書く
- VariableへType Annotationを付ける
- Enum CaseのTypeを明示する
- SwiftUIのAlignment Typeを確認する
- Color、Axis、TextAlignmentなどのTypeを確認する
- Array・DictionaryのElement Typeを明示する
- ClosureのReturn Typeを明示する
- Optional Typeを明示する
- Generic Result Typeを明示する
- Function Overloadを確認する
- Bindingと通常Valueを確認する
- OptionalとNon-Optionalを確認する
- 別ArgumentのType Errorを確認する
- 現在のAPI Signatureを確認する
- より前に表示されているCompiler Errorを先に修正する
まとめ
Swiftの「Cannot infer contextual base in reference to member」は、.active、.center、.redなどの省略Memberが、どのTypeに属するものなのかCompilerがContextから判断できない場合に発生します。
代表的な原因は、VariableのType Annotation不足、Enum CaseのContext不足、Function Overload、Generic Type、Optional、Closure、SwiftUIのAlignmentやBindingなどです。
最も簡単な解決方法は、UserState.active、Alignment.center、Color.redのようにBase Typeを明示することです。
また、let state: UserState = .activeのようにVariable側へExpected Typeを与える方法も有効です。
SwiftUIではAlignment、HorizontalAlignment、VerticalAlignment、TextAlignmentなど似たTypeがあるため、そのModifierやView Initializerが要求するTypeを確認してください。
Typeを明示しても直らない場合は、省略Memberそのものではなく、Argument Label、別ArgumentのType、Binding、Optional、Generic Parameterなどが原因でExpected Typeを失っていないか確認することが重要です。
