@@ -811,59 +811,11 @@ class CompletionContextFinder : public ASTWalker {
811811
812812} // end namespace
813813
814- // Determine if the target expression is the implicit BinaryExpr generated for
815- // pattern-matching in a switch/if/guard case (<completion> ~= matchValue).
816- static bool isForPatternMatch (SolutionApplicationTarget &target) {
817- if (target.getExprContextualTypePurpose () != CTP_Condition)
818- return false ;
819- Expr *condition = target.getAsExpr ();
820- if (!condition->isImplicit ())
821- return false ;
822- if (auto *BE = dyn_cast<BinaryExpr>(condition)) {
823- Identifier id;
824- if (auto *ODRE = dyn_cast<OverloadedDeclRefExpr>(BE->getFn ())) {
825- id = ODRE->getDecls ().front ()->getBaseIdentifier ();
826- } else if (auto *DRE = dyn_cast<DeclRefExpr>(BE->getFn ())) {
827- id = DRE->getDecl ()->getBaseIdentifier ();
828- }
829- if (id != target.getDeclContext ()->getASTContext ().Id_MatchOperator )
830- return false ;
831- return isa<CodeCompletionExpr>(BE->getLHS ());
832- }
833- return false ;
834- }
835-
836- // / Remove any solutions from the provided vector that both require fixes and have a
837- // / score worse than the best.
814+ // / Remove any solutions from the provided vector that both require fixes and
815+ // / have a score worse than the best.
838816static void filterSolutions (SolutionApplicationTarget &target,
839817 SmallVectorImpl<Solution> &solutions,
840818 CodeCompletionExpr *completionExpr) {
841- // FIXME: this is only needed because in pattern matching position, the
842- // code completion expression always becomes an expression pattern, which
843- // requires the ~= operator to be defined on the type being matched against.
844- // Pattern matching against an enum doesn't require that however, so valid
845- // solutions always end up having fixes. This is a problem because there will
846- // always be a valid solution as well. Optional defines ~= between Optional
847- // and _OptionalNilComparisonType (which defines a nilLiteral initializer),
848- // and the matched-against value can implicitly be made Optional if it isn't
849- // already, so _OptionalNilComparisonType is always a valid solution for the
850- // completion. That only generates the 'nil' completion, which is rarely what
851- // the user intends to write in this position and shouldn't be preferred over
852- // the other formed solutions (which require fixes). We should generate enum
853- // pattern completions separately, but for now ignore the
854- // _OptionalNilComparisonType solution.
855- if (isForPatternMatch (target) && completionExpr) {
856- solutions.erase (llvm::remove_if (solutions, [&](const Solution &S) {
857- ASTContext &ctx = S.getConstraintSystem ().getASTContext ();
858- if (!S.hasType (completionExpr))
859- return false ;
860- if (auto ty = S.getResolvedType (completionExpr))
861- if (auto *NTD = ty->getAnyNominal ())
862- return NTD->getBaseIdentifier () == ctx.Id_OptionalNilComparisonType ;
863- return false ;
864- }), solutions.end ());
865- }
866-
867819 if (solutions.size () <= 1 )
868820 return ;
869821
@@ -1286,6 +1238,69 @@ sawSolution(const constraints::Solution &S) {
12861238 }
12871239}
12881240
1241+ // / If the code completion variable occurs in a pattern matching position, we
1242+ // / have an AST that looks like this.
1243+ // / \code
1244+ // / (binary_expr implicit type='$T3'
1245+ // / (overloaded_decl_ref_expr function_ref=compound decls=[
1246+ // / Swift.(file).~=,
1247+ // / Swift.(file).Optional extension.~=])
1248+ // / (tuple_expr implicit type='($T1, (OtherEnum))'
1249+ // / (code_completion_expr implicit type='$T1')
1250+ // / (declref_expr implicit decl=swift_ide_test.(file).foo(x:).$match)))
1251+ // / \endcode
1252+ // / If the code completion expression occurs in such an AST, return the
1253+ // / declaration of the \c $match variable, otherwise return \c nullptr.
1254+ VarDecl *getMatchVarIfInPatternMatch (CodeCompletionExpr *CompletionExpr,
1255+ ConstraintSystem &CS) {
1256+ auto &Context = CS.getASTContext ();
1257+
1258+ TupleExpr *ArgTuple =
1259+ dyn_cast_or_null<TupleExpr>(CS.getParentExpr (CompletionExpr));
1260+ if (!ArgTuple || !ArgTuple->isImplicit () || ArgTuple->getNumElements () != 2 ) {
1261+ return nullptr ;
1262+ }
1263+
1264+ auto Binary = dyn_cast_or_null<BinaryExpr>(CS.getParentExpr (ArgTuple));
1265+ if (!Binary || !Binary->isImplicit ()) {
1266+ return nullptr ;
1267+ }
1268+
1269+ auto CalledOperator = Binary->getFn ();
1270+ if (!CalledOperator || !CalledOperator->isImplicit ()) {
1271+ return nullptr ;
1272+ }
1273+ // The reference to the ~= operator might be an OverloadedDeclRefExpr or a
1274+ // DeclRefExpr, depending on how many ~= operators are viable.
1275+ if (auto Overloaded =
1276+ dyn_cast_or_null<OverloadedDeclRefExpr>(CalledOperator)) {
1277+ if (!llvm::all_of (Overloaded->getDecls (), [&Context](ValueDecl *D) {
1278+ return D->getBaseName () == Context.Id_MatchOperator ;
1279+ })) {
1280+ return nullptr ;
1281+ }
1282+ } else if (auto Ref = dyn_cast_or_null<DeclRefExpr>(CalledOperator)) {
1283+ if (Ref->getDecl ()->getBaseName () != Context.Id_MatchOperator ) {
1284+ return nullptr ;
1285+ }
1286+ } else {
1287+ return nullptr ;
1288+ }
1289+
1290+ auto MatchArg = dyn_cast_or_null<DeclRefExpr>(ArgTuple->getElement (1 ));
1291+ if (!MatchArg || !MatchArg->isImplicit ()) {
1292+ return nullptr ;
1293+ }
1294+
1295+ auto MatchVar = MatchArg->getDecl ();
1296+ if (MatchVar && MatchVar->isImplicit () &&
1297+ MatchVar->getBaseName () == Context.Id_PatternMatchVar ) {
1298+ return dyn_cast<VarDecl>(MatchVar);
1299+ } else {
1300+ return nullptr ;
1301+ }
1302+ }
1303+
12891304void UnresolvedMemberTypeCheckCompletionCallback::
12901305sawSolution (const constraints::Solution &S) {
12911306 GotCallback = true ;
@@ -1295,18 +1310,34 @@ sawSolution(const constraints::Solution &S) {
12951310 // If the type couldn't be determined (e.g. because there isn't any context
12961311 // to derive it from), let's not attempt to do a lookup since it wouldn't
12971312 // produce any useful results anyway.
1298- if (!ExpectedTy || ExpectedTy->is <UnresolvedType>())
1299- return ;
1300-
1301- // If ExpectedTy is a duplicate of any other result, ignore this solution.
1302- if (llvm::any_of (Results, [&](const Result &R) {
1303- return R.ExpectedTy ->isEqual (ExpectedTy);
1304- })) {
1305- return ;
1313+ if (ExpectedTy && !ExpectedTy->is <UnresolvedType>()) {
1314+ // If ExpectedTy is a duplicate of any other result, ignore this solution.
1315+ if (!llvm::any_of (ExprResults, [&](const ExprResult &R) {
1316+ return R.ExpectedTy ->isEqual (ExpectedTy);
1317+ })) {
1318+ bool SingleExprBody =
1319+ isImplicitSingleExpressionReturn (CS, CompletionExpr);
1320+ ExprResults.push_back ({ExpectedTy, SingleExprBody});
1321+ }
13061322 }
13071323
1308- bool SingleExprBody = isImplicitSingleExpressionReturn (CS, CompletionExpr);
1309- Results.push_back ({ExpectedTy, SingleExprBody});
1324+ if (auto MatchVar = getMatchVarIfInPatternMatch (CompletionExpr, CS)) {
1325+ Type MatchVarType;
1326+ // If the MatchVar has an explicit type, it's not part of the solution. But
1327+ // we can look it up in the constraint system directly.
1328+ if (auto T = S.getConstraintSystem ().getVarType (MatchVar)) {
1329+ MatchVarType = T;
1330+ } else {
1331+ MatchVarType = S.getResolvedType (MatchVar);
1332+ }
1333+ if (MatchVarType && !MatchVarType->is <UnresolvedType>()) {
1334+ if (!llvm::any_of (EnumPatternTypes, [&](const Type &R) {
1335+ return R->isEqual (MatchVarType);
1336+ })) {
1337+ EnumPatternTypes.push_back (MatchVarType);
1338+ }
1339+ }
1340+ }
13101341}
13111342
13121343void KeyPathTypeCheckCompletionCallback::sawSolution (
0 commit comments