@@ -3668,6 +3668,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
3668
3668
DeclContext *useDC, FunctionRefKind functionRefKind,
3669
3669
ArrayRef<OverloadChoice> outerAlternatives, TypeMatchOptions flags,
3670
3670
ConstraintLocatorBuilder locatorB) {
3671
+ // We'd need to record original base type because it might be a type
3672
+ // variable representing another missing member.
3673
+ auto origBaseTy = baseTy;
3671
3674
// Resolve the base type, if we can. If we can't resolve the base type,
3672
3675
// then we can't solve this constraint.
3673
3676
baseTy = simplifyType (baseTy, flags);
@@ -3715,6 +3718,13 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
3715
3718
// If the lookup found no hits at all (either viable or unviable), diagnose it
3716
3719
// as such and try to recover in various ways.
3717
3720
if (shouldAttemptFixes ()) {
3721
+ // Let's record missing member in constraint system, this helps to prevent
3722
+ // stacking up fixes for the same member, because e.g. if its base was of
3723
+ // optional type, we'd re-introduce member constraint with optional stripped
3724
+ // off to see if the problem is related to base not being explicitly unwrapped.
3725
+ if (!MissingMembers.insert (locator))
3726
+ return SolutionKind::Error;
3727
+
3718
3728
if (baseObjTy->getOptionalObjectType ()) {
3719
3729
// If the base type was an optional, look through it.
3720
3730
@@ -3760,15 +3770,22 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
3760
3770
return SolutionKind::Solved;
3761
3771
}
3762
3772
3773
+ auto solveWithNewBaseOrName = [&](Type baseType,
3774
+ DeclName memberName) -> SolutionKind {
3775
+ // Let's re-enable fixes for this member, because
3776
+ // the base or member name has been changed.
3777
+ MissingMembers.remove (locator);
3778
+ return simplifyMemberConstraint (kind, baseType, memberName, memberTy,
3779
+ useDC, functionRefKind, outerAlternatives,
3780
+ flags, locatorB);
3781
+ };
3782
+
3763
3783
if (auto *funcType = baseTy->getAs <FunctionType>()) {
3764
3784
// We can't really suggest anything useful unless
3765
3785
// function takes no arguments, otherwise it
3766
3786
// would make sense to report this a missing member.
3767
3787
if (funcType->getNumParams () == 0 ) {
3768
- auto result = simplifyMemberConstraint (
3769
- kind, funcType->getResult (), member, memberTy, useDC,
3770
- functionRefKind, outerAlternatives, flags, locatorB);
3771
-
3788
+ auto result = solveWithNewBaseOrName (funcType->getResult (), member);
3772
3789
// If there is indeed a member with given name in result type
3773
3790
// let's return, otherwise let's fall-through and report
3774
3791
// this problem as a missing member.
@@ -3781,16 +3798,59 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
3781
3798
3782
3799
// Instead of using subscript operator spelled out `subscript` directly.
3783
3800
if (member.getBaseName () == getTokenText (tok::kw_subscript)) {
3784
- auto result = simplifyMemberConstraint (
3785
- kind, baseTy, DeclBaseName::createSubscript (), memberTy, useDC,
3786
- functionRefKind, {}, flags, locatorB);
3787
-
3801
+ auto result =
3802
+ solveWithNewBaseOrName (baseTy, DeclBaseName::createSubscript ());
3788
3803
// Looks like it was indeed meant to be a subscript operator.
3789
3804
if (result == SolutionKind::Solved)
3790
3805
return recordFix (UseSubscriptOperator::create (*this , locator))
3791
3806
? SolutionKind::Error
3792
3807
: SolutionKind::Solved;
3793
3808
}
3809
+
3810
+ // FIXME(diagnostics): This is more of a hack than anything.
3811
+ // Let's not try to suggest that there is no member related to an
3812
+ // obscure underscored type, the real problem would be somewhere
3813
+ // else. This helps to diagnose pattern matching cases.
3814
+ {
3815
+ if (auto *metatype = baseTy->getAs <MetatypeType>()) {
3816
+ auto instanceTy = metatype->getInstanceType ();
3817
+ if (auto *NTD = instanceTy->getAnyNominal ()) {
3818
+ if (NTD->getName () == getASTContext ().Id_OptionalNilComparisonType )
3819
+ return SolutionKind::Error;
3820
+ }
3821
+ }
3822
+ }
3823
+
3824
+ // FIXME(diagnostics): Errors related to `AnyObject` could be diagnosed
3825
+ // better in the future, relevant failure information has to be extracted
3826
+ // from `performMemberLookup` result, in order to figure out if it was a
3827
+ // simple labeling or # of arguments mismatch, or member with requested name
3828
+ // really doesn't exist.
3829
+ if (baseTy->isAnyObject ())
3830
+ return SolutionKind::Error;
3831
+
3832
+ result = performMemberLookup (kind, member, baseTy, functionRefKind, locator,
3833
+ /* includeInaccessibleMembers*/ true );
3834
+
3835
+ // FIXME(diagnostics): If there were no viable results, but there are
3836
+ // unviable ones, we'd have to introduce fix for each specific problem.
3837
+ if (!result.UnviableCandidates .empty ())
3838
+ return SolutionKind::Error;
3839
+
3840
+ // Since member with given base and name doesn't exist, let's try to
3841
+ // fake its presence based on use, that makes it possible to diagnose
3842
+ // problems related to member lookup more precisely.
3843
+ auto *fix =
3844
+ DefineMemberBasedOnUse::create (*this , origBaseTy, member, locator);
3845
+ if (recordFix (fix))
3846
+ return SolutionKind::Error;
3847
+
3848
+ // Allow member type to default to `Any` to make it possible to form
3849
+ // solutions when contextual type of the result cannot be deduced e.g.
3850
+ // `let _ = x.foo`.
3851
+ addConstraint (ConstraintKind::Defaultable, memberTy,
3852
+ getASTContext ().TheAnyType , locator);
3853
+ return SolutionKind::Solved;
3794
3854
}
3795
3855
return SolutionKind::Error;
3796
3856
}
@@ -4508,6 +4568,25 @@ ConstraintSystem::simplifyApplicableFnConstraint(
4508
4568
// following: $T1 -> $T2.
4509
4569
assert (type1->is <FunctionType>());
4510
4570
4571
+ // Let's check if this member couldn't be found and is fixed
4572
+ // to exist based on its usage.
4573
+ if (auto *memberTy = type2->getAs <TypeVariableType>()) {
4574
+ auto *locator = memberTy->getImpl ().getLocator ();
4575
+ if (MissingMembers.count (locator)) {
4576
+ auto *funcTy = type1->castTo <FunctionType>();
4577
+ // Bind type variable associated with member to a type of argument
4578
+ // application, which makes it seem like member exists with the
4579
+ // types of the parameters matching argument types exactly.
4580
+ addConstraint (ConstraintKind::Bind, memberTy, funcTy, locator);
4581
+ // There might be no contextual type for result of the application,
4582
+ // in cases like `let _ = x.foo()`, so let's default result to `Any`
4583
+ // to make expressions like that type-check.
4584
+ addConstraint (ConstraintKind::Defaultable, funcTy->getResult (),
4585
+ getASTContext ().TheAnyType , locator);
4586
+ return SolutionKind::Solved;
4587
+ }
4588
+ }
4589
+
4511
4590
// Drill down to the concrete type on the right hand side.
4512
4591
type2 = getFixedTypeRecursive (type2, flags, /* wantRValue=*/ true );
4513
4592
auto desugar2 = type2->getDesugaredType ();
@@ -5461,6 +5540,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
5461
5540
case FixKind::AddConformance:
5462
5541
case FixKind::AutoClosureForwarding:
5463
5542
case FixKind::RemoveUnwrap:
5543
+ case FixKind::DefineMemberBasedOnUse:
5464
5544
llvm_unreachable (" handled elsewhere" );
5465
5545
}
5466
5546
0 commit comments