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

View File

@@ -3738,13 +3738,13 @@ matchCallArguments(ConstraintSystem &cs,
/// subscript, etc.), find the underlying target expression.
Expr *getArgumentLabelTargetExpr(Expr *fn);
/// Returns true if a reference to a declaration on a given base type will
/// apply its curried self parameter, assuming it has one.
/// Returns true if a reference to a member on a given base type will apply its
/// curried self parameter, assuming it has one.
///
/// 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
/// 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
/// given parameter depth cannot be used with the given value.

View File

@@ -223,3 +223,17 @@ func rdar46459603() {
_ = [arr.values] == [[e]]
// 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)
}