diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 5c04d1aefce..5ea518d6a62 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -2129,15 +2129,19 @@ bool ContextualFailure::diagnoseAsError() { return false; } - case ConstraintLocator::Member: - case ConstraintLocator::FunctionResult: - case ConstraintLocator::UnresolvedMember: { + case ConstraintLocator::UnresolvedMemberChainResult: { auto &solution = getSolution(); - auto locator = getConstraintLocator(anchor, - isExpr(anchor) - ? ConstraintLocator::UnresolvedMember - : ConstraintLocator::Member); - auto overload = getOverloadChoiceIfAvailable(locator); + auto member = anchor; + if (auto *CE = getAsExpr(anchor)) + member = CE->getFn(); + + auto kind = ConstraintLocator::Member; + if (isExpr(anchor)) + kind = ConstraintLocator::UnresolvedMember; + else if (isExpr(anchor)) + kind = ConstraintLocator::SubscriptMember; + auto overload = getOverloadChoiceIfAvailable(getConstraintLocator(member, + kind)); if (!(overload && overload->choice.isDecl())) return false; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 91f8ad9bf8b..cfe2e2bc2c2 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -849,7 +849,6 @@ namespace { } Type addUnresolvedMemberChainConstraints(Expr *expr, Type resultTy, - ConstraintLocator *resultLocator, unsigned additionalOptions = 0) { // If this is a member chain hanging off of an UnresolvedMemberExpr, // and we're at the last element of the chain, then the contextual type @@ -858,14 +857,16 @@ namespace { auto *chainBaseExpr = CS.getMemberChainBase(expr); if (auto *UME = dyn_cast(chainBaseExpr)) { // Create a new type variable representing the result of the chain. - auto chainResultTy = CS.createTypeVariable(resultLocator, + auto locator = CS.getConstraintLocator(expr, + ConstraintLocator::UnresolvedMemberChainResult); + auto chainResultTy = CS.createTypeVariable(locator, additionalOptions | TVO_CanBindToHole | TVO_CanBindToNoEscape); auto chainBaseTy = CS.getUnresolvedMemberBaseType(UME); // The result of this element of the chain must be convertible to the // contextual type, and the contextual type must be equal to the base. CS.addConstraint(ConstraintKind::Conversion, resultTy, chainResultTy, - resultLocator); + locator); CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, CS.getConstraintLocator(UME, ConstraintLocator::MemberRefBase)); @@ -1487,10 +1488,9 @@ namespace { // If there is an argument, apply it. if (auto arg = expr->getArgument()) { // Create a new type variable for the result of the function. - auto outputLocator = CS.getConstraintLocator(expr, - ConstraintLocator::FunctionResult); - auto outputTy = CS.createTypeVariable(outputLocator, - TVO_CanBindToNoEscape); + auto outputTy = CS.createTypeVariable( + CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), + TVO_CanBindToNoEscape); // The function/enum case must be callable with the given argument. @@ -1509,13 +1509,12 @@ namespace { CS.getConstraintLocator(expr), {expr->getArgumentLabels(), expr->getUnlabeledTrailingClosureIndex()}); - return addUnresolvedMemberChainConstraints(expr, outputTy, - outputLocator); + return addUnresolvedMemberChainConstraints(expr, outputTy); } // Otherwise, add the usual constraints for an element of an unresolved // member chain. - return addUnresolvedMemberChainConstraints(expr, memberTy, memberLocator, + return addUnresolvedMemberChainConstraints(expr, memberTy, TVO_CanBindToLValue); } @@ -1586,7 +1585,6 @@ namespace { expr->getOuterAlternatives()); return addUnresolvedMemberChainConstraints(expr, resultTy, - CS.getConstraintLocator(expr, ConstraintLocator::Member), TVO_CanBindToLValue); } @@ -1750,10 +1748,8 @@ namespace { expr->getIndex(), decl, expr->getArgumentLabels(), expr->getUnlabeledTrailingClosureIndex()); - auto resultLocator = CS.getConstraintLocator(expr, - ConstraintLocator::FunctionResult); - return addUnresolvedMemberChainConstraints(expr, resultTy, resultLocator, + return addUnresolvedMemberChainConstraints(expr, resultTy, TVO_CanBindToLValue); } @@ -2938,13 +2934,8 @@ namespace { } // If the ApplyExpr is a CallExpr, add chain constraints as necessary. - if (isa(expr)) { - auto resultLocator = CS.getConstraintLocator(expr, - ConstraintLocator::FunctionResult); - - return addUnresolvedMemberChainConstraints(expr, resultType, - resultLocator); - } + if (isa(expr)) + return addUnresolvedMemberChainConstraints(expr, resultType); return resultType; } @@ -3256,7 +3247,7 @@ namespace { CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(expr->getSubExpr()), objectTy, locator); - return addUnresolvedMemberChainConstraints(expr, objectTy, locator, + return addUnresolvedMemberChainConstraints(expr, objectTy, TVO_CanBindToLValue); } @@ -3292,7 +3283,7 @@ namespace { CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(expr->getSubExpr()), objectTy, locator); - return addUnresolvedMemberChainConstraints(expr, objectTy, locator); + return addUnresolvedMemberChainConstraints(expr, objectTy); } Type visitOpenExistentialExpr(OpenExistentialExpr *expr) { diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 274fc105569..7a3ce7d18ee 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4135,20 +4135,6 @@ bool ConstraintSystem::repairFailures( } case ConstraintLocator::FunctionResult: { - // FIXME: Is this necessary? - if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes, - locator)) - break; - - // If this mismatch occurs at the tail of an unresolved member chain, - // there's a contextual mismatch. - if (isUnresolvedMemberChainTail(anchor)) { - auto *fix = IgnoreContextualType::create(*this, lhs, rhs, - getConstraintLocator(locator)); - conversionsOrFixes.push_back(fix); - break; - } - auto *loc = getConstraintLocator(anchor, {path.begin(), path.end() - 1}); // If this is a mismatch between contextual type and (trailing) // closure with explicitly specified result type let's record it @@ -4195,16 +4181,6 @@ bool ConstraintSystem::repairFailures( repairByInsertingExplicitCall(lhs, rhs)) return true; } - - // If this mismatch occurs at the tail of an unresolved member chain, - // there's a contextual mismatch. - if (isUnresolvedMemberChainTail(anchor)) { - auto *fix = IgnoreContextualType::create(*this, lhs, rhs, - getConstraintLocator(locator)); - conversionsOrFixes.push_back(fix); - break; - } - break; } @@ -4330,10 +4306,7 @@ bool ConstraintSystem::repairFailures( break; } - case ConstraintLocator::UnresolvedMember: { - if (!isExpr(anchor)) - break; - + case ConstraintLocator::UnresolvedMemberChainResult: { if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes, locator)) break; diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp index c5b4a864e4e..708d90d7dc6 100644 --- a/lib/Sema/ConstraintLocator.cpp +++ b/lib/Sema/ConstraintLocator.cpp @@ -81,6 +81,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const { case ConstraintLocator::TernaryBranch: case ConstraintLocator::PatternMatch: case ConstraintLocator::ArgumentAttribute: + case ConstraintLocator::UnresolvedMemberChainResult: return 0; case ConstraintLocator::FunctionArgument: @@ -483,6 +484,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const { break; } + + case UnresolvedMemberChainResult: + out << "unresolved chain result"; + break; } } out << ']'; diff --git a/lib/Sema/ConstraintLocatorPathElts.def b/lib/Sema/ConstraintLocatorPathElts.def index 67228bcbc55..435d20b74ec 100644 --- a/lib/Sema/ConstraintLocatorPathElts.def +++ b/lib/Sema/ConstraintLocatorPathElts.def @@ -192,6 +192,9 @@ CUSTOM_LOCATOR_PATH_ELT(PatternMatch) /// of a problem. CUSTOM_LOCATOR_PATH_ELT(ArgumentAttribute) +/// The result of a chain of member accesses off an UnresolvedMemberExpr +SIMPLE_LOCATOR_PATH_ELT(UnresolvedMemberChainResult) + #undef LOCATOR_PATH_ELT #undef CUSTOM_LOCATOR_PATH_ELT #undef SIMPLE_LOCATOR_PATH_ELT diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 0f518e4695a..322dc620c19 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3859,6 +3859,11 @@ void constraints::simplifyLocator(ASTNode &anchor, break; } + case ConstraintLocator::UnresolvedMemberChainResult: { + path = path.slice(1); + continue; + } + default: // FIXME: Lots of other cases to handle. break; diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index cb2f16f2669..a9018f1a302 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3086,16 +3086,6 @@ public: return parent == nullptr || !isMemberChainMember(parent); } - /// Whether this node sits at the end of a member chain that hangs off an - /// \c UnresolvedMemberExpr at the base. - bool isUnresolvedMemberChainTail(ASTNode node) { - if (auto *expr = getAsExpr(node)) - return isMemberChainTail(expr) - && isa(getMemberChainBase(expr)); - else - return false; - } - public: /// Whether we should attempt to fix problems. diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index c8f468ace2e..9333047a27f 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -50,6 +50,7 @@ struct ImplicitMembers: Equatable { subscript(func arg: Void) -> (() -> ImplicitMembers) { { ImplicitMembers() } } subscript(funcOptional arg: Void) -> (() -> ImplicitMembers?) { { ImplicitMembers() } } subscript(optionalFunc arg: Void) -> (() -> ImplicitMembers)? { { ImplicitMembers() } } + subscript(other arg: Void) -> Other { Other() } } let _: ImplicitMembers = .implicit @@ -100,18 +101,32 @@ let _: ImplicitMembers = .createOptional()!.anotherOptional! let _: ImplicitMembers = .optional!.getAnotherOptional()! let _: ImplicitMembers = .createOptional()!.getAnotherOptional()! +let _: ImplicitMembers = .optional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{35-35= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{35-35=!}} +let _: ImplicitMembers = .implicit.anotherOptional // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{51-51= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{51-51=!}} +let _: ImplicitMembers = .createOptional() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{43-43= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{43-43=!}} +let _: ImplicitMembers = .implicit.getAnotherOptional() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{56-56= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{56-56=!}} +let _: ImplicitMembers = .implicit[optional: ()] // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{49-49= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{49-49=!}} +let _: ImplicitMembers = .implicit[funcOptional: ()]() // expected-error {{value of optional type 'ImplicitMembers?' must be unwrapped to a value of type 'ImplicitMembers'}} expected-note {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{55-55= ?? <#default value#>}} expected-note {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{55-55=!}} + +// FIXME: Improve these diagnostics (should probably offer unwrapping, as above) +let _: ImplicitMembers = .implicit.anotherOptional?.another // expected-error{{cannot infer contextual base in reference to member 'implicit'}} expected-error{{cannot convert value of type 'Optional<_>' to specified type 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit[optionalFunc: ()]?() // expected-error{{cannot infer contextual base in reference to member 'implicit'}} expected-error{{cannot convert value of type 'Optional<_>' to specified type 'ImplicitMembers'}} + + let _: ImplicitMembers = .other.implicit let _: ImplicitMembers = .implicit.anotherOther.implicit let _: ImplicitMembers = .createOther().implicit let _: ImplicitMembers = .implicit.getAnotherOther().implicit +let _: ImplicitMembers = .implicit[other: ()].implicit let _: ImplicitMembers = .other // expected-error {{member 'other' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} -let _: ImplicitMembers = .implicit.anotherOther // expected-error {{member 'implicit' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit.anotherOther // expected-error {{member 'anotherOther' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod() // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMember.another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMember'}} let _: ImplicitMembers = .implicit.anotherOther.nonDeclaredMethod().another // expected-error {{value of type 'ImplicitMembers.Other' has no member 'nonDeclaredMethod'}} let _: ImplicitMembers = .implicit.getAnotherOther() // expected-error {{member 'getAnotherOther()' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} +let _: ImplicitMembers = .implicit[other: ()] // expected-error {{member 'subscript(other:)' in 'ImplicitMembers' produces result of type 'ImplicitMembers.Other', but context expects 'ImplicitMembers'}} let _: ImplicitMembers? = .implicit.another let _: ImplicitMembers? = .implicit.anotherOptional