@@ -7109,6 +7109,95 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
7109
7109
return nullptr ;
7110
7110
}
7111
7111
7112
+ // / Diagnose if the base type is optional, we're referring to a nominal
7113
+ // / type member via the dot syntax and the member name matches
7114
+ // / Optional<T>.{member} or a .none member inferred as non-optional static
7115
+ // / member e.g. let _ : Foo? = .none where Foo has a static member none.
7116
+ static bool attemptUnresolvedMemberFix (ConstraintSystem &cs,
7117
+ ConstraintKind kind, Type baseTy,
7118
+ DeclNameRef member,
7119
+ FunctionRefKind functionRefKind,
7120
+ ConstraintLocator *locator,
7121
+ MemberLookupResult result) {
7122
+
7123
+ if (kind != ConstraintKind::UnresolvedValueMember)
7124
+ return false ;
7125
+
7126
+ // None or only one viable candidate, there is no ambiguity.
7127
+ if (result.ViableCandidates .size () <= 1 )
7128
+ return false ;
7129
+
7130
+ // Only diagnose those situations for static members.
7131
+ if (!baseTy->is <MetatypeType>())
7132
+ return false ;
7133
+
7134
+ // Don't diagnose for function members e.g. Foo? = .none(0).
7135
+ if (functionRefKind != FunctionRefKind::Unapplied)
7136
+ return false ;
7137
+
7138
+ Type underlyingBaseType = baseTy->getMetatypeInstanceType ();
7139
+ if (!underlyingBaseType->getNominalOrBoundGenericNominal ())
7140
+ return false ;
7141
+
7142
+ if (!underlyingBaseType->getOptionalObjectType ())
7143
+ return false ;
7144
+
7145
+ auto unwrappedType = underlyingBaseType->lookThroughAllOptionalTypes ();
7146
+ bool allOptionalBaseCandidates = true ;
7147
+ auto filterViableCandidates =
7148
+ [&](SmallVector<OverloadChoice, 4 > &candidates,
7149
+ SmallVector<OverloadChoice, 4 > &viableCandidates,
7150
+ bool &allOptionalBase) {
7151
+ for (OverloadChoice choice : candidates) {
7152
+ if (!choice.isDecl ())
7153
+ continue ;
7154
+
7155
+ auto memberDecl = choice.getDecl ();
7156
+ if (isa<FuncDecl>(memberDecl))
7157
+ continue ;
7158
+ if (memberDecl->isInstanceMember ())
7159
+ continue ;
7160
+
7161
+ allOptionalBase &= bool (choice.getBaseType ()
7162
+ ->getMetatypeInstanceType ()
7163
+ ->getOptionalObjectType ());
7164
+
7165
+ if (auto EED = dyn_cast<EnumElementDecl>(memberDecl)) {
7166
+ if (!EED->hasAssociatedValues ())
7167
+ viableCandidates.push_back (choice);
7168
+ } else if (auto VD = dyn_cast<VarDecl>(memberDecl)) {
7169
+ if (unwrappedType->hasTypeVariable () ||
7170
+ VD->getInterfaceType ()->isEqual (unwrappedType))
7171
+ viableCandidates.push_back (choice);
7172
+ }
7173
+ }
7174
+ };
7175
+
7176
+ SmallVector<OverloadChoice, 4 > viableCandidates;
7177
+ filterViableCandidates (result.ViableCandidates , viableCandidates,
7178
+ allOptionalBaseCandidates);
7179
+
7180
+ // Also none or only one viable candidate after filtering candidates, there is
7181
+ // no ambiguity.
7182
+ if (viableCandidates.size () <= 1 )
7183
+ return false ;
7184
+
7185
+ // Right now, name lookup only unwraps a single layer of optionality, which
7186
+ // for cases where base type is a multi-optional type e.g. Foo?? so, it only
7187
+ // finds optional base candidates. To produce the correct warning perform an
7188
+ // extra lookup on unwrapped type is required.
7189
+ if (!allOptionalBaseCandidates)
7190
+ return true ;
7191
+
7192
+ MemberLookupResult unwrappedResult = cs.performMemberLookup (
7193
+ kind, member, MetatypeType::get (unwrappedType), functionRefKind, locator,
7194
+ /* includeInaccessibleMembers*/ false );
7195
+ SmallVector<OverloadChoice, 4 > unwrappedViableCandidates;
7196
+ filterViableCandidates (unwrappedResult.ViableCandidates ,
7197
+ unwrappedViableCandidates, allOptionalBaseCandidates);
7198
+ return !unwrappedViableCandidates.empty ();
7199
+ }
7200
+
7112
7201
ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint (
7113
7202
ConstraintKind kind, Type baseTy, DeclNameRef member, Type memberTy,
7114
7203
DeclContext *useDC, FunctionRefKind functionRefKind,
@@ -7290,7 +7379,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
7290
7379
}
7291
7380
7292
7381
if (!result.UnviableCandidates .empty ()) {
7293
- // Generate constraints for unvailable choices if they have a fix,
7382
+ // Generate constraints for unavailable choices if they have a fix,
7294
7383
// and disable them by default, they'd get picked up in the "salvage" mode.
7295
7384
generateConstraints (
7296
7385
candidates, memberTy, result.UnviableCandidates , useDC, locator,
@@ -7301,6 +7390,21 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
7301
7390
});
7302
7391
}
7303
7392
7393
+ // Attempt to record a warning where the unresolved member could be
7394
+ // ambiguous with optional member. e.g.
7395
+ // enum Foo {
7396
+ // case none
7397
+ // }
7398
+ //
7399
+ // let _: Foo? = .none // Although base is inferred as Optional.none
7400
+ // it could be also.
7401
+ if (attemptUnresolvedMemberFix (*this , kind, baseObjTy, member,
7402
+ functionRefKind, locator, result)) {
7403
+ auto *fix = SpecifyBaseTypeForOptionalUnresolvedMember::create (
7404
+ *this , member, locator);
7405
+ (void )recordFix (fix);
7406
+ }
7407
+
7304
7408
if (!candidates.empty ()) {
7305
7409
addOverloadSet (candidates, locator);
7306
7410
return SolutionKind::Solved;
@@ -10234,7 +10338,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
10234
10338
case FixKind::AllowKeyPathWithoutComponents:
10235
10339
case FixKind::IgnoreInvalidResultBuilderBody:
10236
10340
case FixKind::SpecifyContextualTypeForNil:
10237
- case FixKind::AllowRefToInvalidDecl: {
10341
+ case FixKind::AllowRefToInvalidDecl:
10342
+ case FixKind::SpecifyBaseTypeForOptionalUnresolvedMember: {
10238
10343
return recordFix (fix) ? SolutionKind::Error : SolutionKind::Solved;
10239
10344
}
10240
10345
@@ -10341,7 +10446,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
10341
10446
if (auto *fnType1 = type1->getAs <FunctionType>()) {
10342
10447
// If this is a contextual mismatch between two
10343
10448
// function types which we couldn't find a more
10344
- // speficit fix for. Let's assume that such types
10449
+ // specific fix for. Let's assume that such types
10345
10450
// are competely disjoint and adjust impact of
10346
10451
// the fix accordingly.
10347
10452
if (auto *fnType2 = type2->getAs <FunctionType>()) {
0 commit comments