Sema: Check for invalid reference *before* checking for unsupported existential member access

This commit is contained in:
Anthony Latsis
2021-08-13 20:08:04 +03:00
parent 64b8f61b13
commit e49ca21bf0
2 changed files with 61 additions and 40 deletions

View File

@@ -7322,7 +7322,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
// Dig out the instance type and figure out what members of the instance type // Dig out the instance type and figure out what members of the instance type
// we are going to see. // we are going to see.
auto baseTy = candidate.getBaseType(); auto baseTy = candidate.getBaseType();
auto baseObjTy = baseTy->getRValueType(); const auto baseObjTy = baseTy->getRValueType();
bool hasInstanceMembers = false; bool hasInstanceMembers = false;
bool hasInstanceMethods = false; bool hasInstanceMethods = false;
@@ -7369,18 +7369,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
hasInstanceMethods = true; hasInstanceMethods = true;
} }
// If our base is an existential type, we can't make use of any
// member whose signature involves associated types.
if (instanceTy->isExistentialType()) {
if (auto *proto = decl->getDeclContext()->getSelfProtocolDecl()) {
if (!proto->isAvailableInExistential(decl)) {
result.addUnviable(candidate,
MemberLookupResult::UR_UnavailableInExistential);
return;
}
}
}
// If the invocation's argument expression has a favored type, // If the invocation's argument expression has a favored type,
// use that information to determine whether a specific overload for // use that information to determine whether a specific overload for
// the candidate should be favored. // the candidate should be favored.
@@ -7400,6 +7388,20 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
} }
} }
const auto isUnsupportedExistentialMemberAccess = [&] {
// If our base is an existential type, we can't make use of any
// member whose signature involves associated types.
if (instanceTy->isExistentialType()) {
if (auto *proto = decl->getDeclContext()->getSelfProtocolDecl()) {
if (!proto->isAvailableInExistential(decl)) {
return true;
}
}
}
return false;
};
// See if we have an instance method, instance member or static method, // See if we have an instance method, instance member or static method,
// and check if it can be accessed on our base type. // and check if it can be accessed on our base type.
@@ -7413,20 +7415,35 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
? candidate ? candidate
: OverloadChoice(instanceTy, decl, : OverloadChoice(instanceTy, decl,
FunctionRefKind::SingleApply); FunctionRefKind::SingleApply);
// If this is an instance member referenced from metatype
// let's add unviable result to the set because it could be
// either curried reference or an invalid call.
//
// New candidate shouldn't affect performance because such
// choice would only be attempted when solver is in diagnostic mode.
result.addUnviable(choice, MemberLookupResult::UR_InstanceMemberOnType);
bool invalidMethodRef = isa<FuncDecl>(decl) && !hasInstanceMethods; const bool invalidMethodRef = isa<FuncDecl>(decl) && !hasInstanceMethods;
bool invalidMemberRef = !isa<FuncDecl>(decl) && !hasInstanceMembers; const bool invalidMemberRef = !isa<FuncDecl>(decl) && !hasInstanceMembers;
// If this is definitely an invalid way to reference a method or member
// on the metatype, let's stop here. if (invalidMethodRef || invalidMemberRef) {
if (invalidMethodRef || invalidMemberRef) // If this is definitely an invalid way to reference a method or member
// on the metatype, let's stop here.
result.addUnviable(choice,
MemberLookupResult::UR_InstanceMemberOnType);
return; return;
} else if (isUnsupportedExistentialMemberAccess()) {
// If the member reference itself is legal, but it turns out to be an
// unsupported existential member access, do not make further
// assumptions about the correctness of a potential call -- let
// the unsupported member access error prevail.
result.addUnviable(candidate,
MemberLookupResult::UR_UnavailableInExistential);
return;
} else {
// Otherwise, still add an unviable result to the set, because it
// could be an invalid call that was supposed to be performed on an
// instance of the type.
//
// New candidate shouldn't affect performance because such
// choice would only be attempted when solver is in diagnostic mode.
result.addUnviable(choice,
MemberLookupResult::UR_InstanceMemberOnType);
}
} }
// If the underlying type of a typealias is fully concrete, it is legal // If the underlying type of a typealias is fully concrete, it is legal
@@ -7477,6 +7494,12 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
} }
} }
if (isUnsupportedExistentialMemberAccess()) {
result.addUnviable(candidate,
MemberLookupResult::UR_UnavailableInExistential);
return;
}
// If we have an rvalue base, make sure that the result isn't 'mutating' // If we have an rvalue base, make sure that the result isn't 'mutating'
// (only valid on lvalues). // (only valid on lvalues).
if (!baseTy->is<AnyMetatypeType>() && if (!baseTy->is<AnyMetatypeType>() &&

View File

@@ -442,19 +442,19 @@ protocol P1_TypeMemberOnInstanceAndViceVersa {
subscript(invariantSelfSubscript _: Void) -> G<Self> { get } subscript(invariantSelfSubscript _: Void) -> G<Self> { get }
} }
do { do {
// Test that invalid reference errors prevail over unsupported existential
// member accesses.
func test(protoMeta: P1_TypeMemberOnInstanceAndViceVersa.Protocol, func test(protoMeta: P1_TypeMemberOnInstanceAndViceVersa.Protocol,
existMeta: P1_TypeMemberOnInstanceAndViceVersa.Type, existMeta: P1_TypeMemberOnInstanceAndViceVersa.Type,
instance: P1_TypeMemberOnInstanceAndViceVersa) { instance: P1_TypeMemberOnInstanceAndViceVersa) {
// P1_TypeMemberOnInstanceAndViceVersa.Protocol // P1_TypeMemberOnInstanceAndViceVersa.Protocol
// FIXME: These should be diagnosed as invalid references. protoMeta.static_invariantSelfMethod() // expected-error {{static member 'static_invariantSelfMethod' cannot be used on protocol metatype 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'}}
protoMeta.static_invariantSelfMethod() // expected-error {{member 'static_invariantSelfMethod' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'; use a generic constraint instead}} protoMeta.static_invariantSelfProp // expected-error {{static member 'static_invariantSelfProp' cannot be used on protocol metatype 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'}}
protoMeta.static_invariantSelfProp // expected-error {{member 'static_invariantSelfProp' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'; use a generic constraint instead}} protoMeta[static_invariantSelfSubscript: ()] // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'}}
protoMeta[static_invariantSelfSubscript: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'; use a generic constraint instead}}
_ = protoMeta.covariantSelfMethod // ok _ = protoMeta.covariantSelfMethod // ok
protoMeta.invariantSelfMethod // expected-error {{member 'invariantSelfMethod' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'; use a generic constraint instead}} protoMeta.invariantSelfMethod // expected-error {{member 'invariantSelfMethod' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'; use a generic constraint instead}}
// FIXME: These should be diagnosed as invalid references. protoMeta.invariantSelfProp // expected-error {{instance member 'invariantSelfProp' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}}
protoMeta.invariantSelfProp // expected-error {{member 'invariantSelfProp' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'; use a generic constraint instead}} protoMeta[invariantSelfSubscript: ()] // expected-error {{instance member 'subscript' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}}
protoMeta[invariantSelfSubscript: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Protocol'; use a generic constraint instead}}
// P1_TypeMemberOnInstanceAndViceVersa.Type // P1_TypeMemberOnInstanceAndViceVersa.Type
_ = existMeta.static_covariantSelfMethod // ok _ = existMeta.static_covariantSelfMethod // ok
@@ -463,16 +463,14 @@ do {
existMeta.static_invariantSelfMethod // expected-error {{member 'static_invariantSelfMethod' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}} existMeta.static_invariantSelfMethod // expected-error {{member 'static_invariantSelfMethod' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}}
existMeta.static_invariantSelfProp // expected-error {{member 'static_invariantSelfProp' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}} existMeta.static_invariantSelfProp // expected-error {{member 'static_invariantSelfProp' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}}
existMeta[static_invariantSelfSubscript: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}} existMeta[static_invariantSelfSubscript: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}}
// FIXME: These should be diagnosed as invalid references. existMeta.invariantSelfMethod // expected-error {{instance member 'invariantSelfMethod' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}}
existMeta.invariantSelfMethod // expected-error {{member 'invariantSelfMethod' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}} existMeta.invariantSelfProp // expected-error {{instance member 'invariantSelfProp' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}}
existMeta.invariantSelfProp // expected-error {{member 'invariantSelfProp' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}} existMeta[invariantSelfSubscript: ()] // expected-error {{instance member 'subscript' cannot be used on type 'P1_TypeMemberOnInstanceAndViceVersa'}}
existMeta[invariantSelfSubscript: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa.Type'; use a generic constraint instead}}
// P1_TypeMemberOnInstanceAndViceVersa // P1_TypeMemberOnInstanceAndViceVersa
// FIXME: These should be diagnosed as invalid references. instance.static_invariantSelfMethod // expected-error {{static member 'static_invariantSelfMethod' cannot be used on instance of type 'P1_TypeMemberOnInstanceAndViceVersa'}}
instance.static_invariantSelfMethod // expected-error {{member 'static_invariantSelfMethod' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa'; use a generic constraint instead}} instance.static_invariantSelfProp // expected-error {{static member 'static_invariantSelfProp' cannot be used on instance of type 'P1_TypeMemberOnInstanceAndViceVersa'}}
instance.static_invariantSelfProp // expected-error {{member 'static_invariantSelfProp' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa'; use a generic constraint instead}} instance[static_invariantSelfSubscript: ()] // expected-error {{static member 'subscript' cannot be used on instance of type 'P1_TypeMemberOnInstanceAndViceVersa'}}
instance[static_invariantSelfSubscript: ()] // expected-error {{member 'subscript' cannot be used on value of protocol type 'P1_TypeMemberOnInstanceAndViceVersa'; use a generic constraint instead}}
} }
} }