[Sema] Don't assume member refs have base types

- Add a precondition on `doesDeclRefApplyCurriedSelf` to expect
a member decl, and rename it to make the precondition explicit.

- Don't assume that not having a base type means this isn't a member
reference, as member references to static operators don't have base
types.

Resolves SR-10843.
This commit is contained in:
Hamish Knight
2019-06-06 15:58:46 +01:00
parent 623a6adee0
commit 356b3b4150
4 changed files with 28 additions and 13 deletions

View File

@@ -100,17 +100,18 @@ static Optional<unsigned> scoreParamAndArgNameTypo(StringRef paramName,
return dist; return dist;
} }
bool constraints::doesDeclRefApplyCurriedSelf(Type baseTy, bool constraints::doesMemberRefApplyCurriedSelf(Type baseTy,
const ValueDecl *decl) { const ValueDecl *decl) {
// If this isn't a member reference, there's nothing to apply. assert(decl->getDeclContext()->isTypeContext() &&
if (!baseTy || baseTy->is<ModuleType>()) "Expected a member reference");
return false;
// For a reference to an instance method on a metatype, we want to keep the // For a reference to an instance method on a metatype, we want to keep the
// curried self. // curried self.
if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) if (decl->isInstanceMember()) {
if (afd->isInstanceMember() && baseTy->is<AnyMetatypeType>()) assert(baseTy);
if (isa<AbstractFunctionDecl>(decl) && baseTy->is<AnyMetatypeType>())
return false; return false;
}
// Otherwise the reference applies self. // Otherwise the reference applies self.
return true; return true;
@@ -157,7 +158,7 @@ bool constraints::areConservativelyCompatibleArgumentLabels(
// the member lookup applying the curried self at the first level. But there // the member lookup applying the curried self at the first level. But there
// are cases where we can get an unapplied declaration reference back. // are cases where we can get an unapplied declaration reference back.
auto hasAppliedSelf = auto hasAppliedSelf =
decl->hasCurriedSelf() && doesDeclRefApplyCurriedSelf(baseType, decl); decl->hasCurriedSelf() && doesMemberRefApplyCurriedSelf(baseType, decl);
auto *fnType = decl->getInterfaceType()->castTo<AnyFunctionType>(); auto *fnType = decl->getInterfaceType()->castTo<AnyFunctionType>();
if (hasAppliedSelf) { if (hasAppliedSelf) {
@@ -860,7 +861,7 @@ getCalleeDeclAndArgs(ConstraintSystem &cs,
// In most cases where we reference a declaration with a curried self // In most cases where we reference a declaration with a curried self
// parameter, it gets dropped from the type of the reference. // parameter, it gets dropped from the type of the reference.
bool hasAppliedSelf = bool hasAppliedSelf =
decl->hasCurriedSelf() && doesDeclRefApplyCurriedSelf(baseType, decl); decl->hasCurriedSelf() && doesMemberRefApplyCurriedSelf(baseType, decl);
return std::make_tuple(decl, hasAppliedSelf, argLabels, hasTrailingClosure); return std::make_tuple(decl, hasAppliedSelf, argLabels, hasTrailingClosure);
} }

View File

@@ -1222,7 +1222,7 @@ ConstraintSystem::getTypeOfMemberReference(
// Check to see if the self parameter is applied, in which case we'll want to // Check to see if the self parameter is applied, in which case we'll want to
// strip it off later. // strip it off later.
auto hasAppliedSelf = doesDeclRefApplyCurriedSelf(baseObjTy, value); auto hasAppliedSelf = doesMemberRefApplyCurriedSelf(baseObjTy, value);
baseObjTy = baseObjTy->getMetatypeInstanceType(); baseObjTy = baseObjTy->getMetatypeInstanceType();
FunctionType::Param baseObjParam(baseObjTy); FunctionType::Param baseObjParam(baseObjTy);

View File

@@ -3738,13 +3738,13 @@ matchCallArguments(ConstraintSystem &cs,
/// subscript, etc.), find the underlying target expression. /// subscript, etc.), find the underlying target expression.
Expr *getArgumentLabelTargetExpr(Expr *fn); Expr *getArgumentLabelTargetExpr(Expr *fn);
/// Returns true if a reference to a declaration on a given base type will /// Returns true if a reference to a member on a given base type will apply its
/// apply its curried self parameter, assuming it has one. /// curried self parameter, assuming it has one.
/// ///
/// This is true for most member references, however isn't true for things like /// This is true for most member references, however isn't true for things like
/// an instance member being referenced on a metatype, where the curried self /// an instance member being referenced on a metatype, where the curried self
/// parameter remains unapplied. /// parameter remains unapplied.
bool doesDeclRefApplyCurriedSelf(Type baseTy, const ValueDecl *decl); bool doesMemberRefApplyCurriedSelf(Type baseTy, const ValueDecl *decl);
/// Attempt to prove that arguments with the given labels at the /// Attempt to prove that arguments with the given labels at the
/// given parameter depth cannot be used with the given value. /// given parameter depth cannot be used with the given value.

View File

@@ -223,3 +223,17 @@ func rdar46459603() {
_ = [arr.values] == [[e]] _ = [arr.values] == [[e]]
// expected-error@-1 {{protocol type 'Any' cannot conform to 'Equatable' because only concrete types can conform to protocols}} // expected-error@-1 {{protocol type 'Any' cannot conform to 'Equatable' because only concrete types can conform to protocols}}
} }
// SR-10843
infix operator ^^^
func ^^^ (lhs: String, rhs: String) {}
struct SR10843 {
static func ^^^ (lhs: SR10843, rhs: SR10843) {}
}
func sr10843() {
let s = SR10843()
(^^^)(s, s)
_ = (==)(0, 0)
}