mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Sema: Rework resolveTypeInContext()
Separate the "find the correct context" part from "substitute in the base type" part. The former can go away completely after a bit of refactoring.
This commit is contained in:
@@ -47,7 +47,7 @@ public:
|
|||||||
/// \returns The resolved generic type parameter type, which may be \c gp.
|
/// \returns The resolved generic type parameter type, which may be \c gp.
|
||||||
virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp) = 0;
|
virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp) = 0;
|
||||||
|
|
||||||
/// Resolve a reference to a member within a dependent type.
|
/// Resolve a qualified reference to a type member within a dependent type.
|
||||||
///
|
///
|
||||||
/// \param baseTy The base of the member access.
|
/// \param baseTy The base of the member access.
|
||||||
/// \param baseRange The source range covering the base type.
|
/// \param baseRange The source range covering the base type.
|
||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
SourceRange baseRange,
|
SourceRange baseRange,
|
||||||
ComponentIdentTypeRepr *ref) = 0;
|
ComponentIdentTypeRepr *ref) = 0;
|
||||||
|
|
||||||
/// Resolve a reference to an associated type within the 'Self' type
|
/// Resolve an unqualified reference to an associated type of the 'Self' type
|
||||||
/// of a protocol.
|
/// of a protocol.
|
||||||
///
|
///
|
||||||
/// \param selfTy The base of the member access.
|
/// \param selfTy The base of the member access.
|
||||||
@@ -69,21 +69,15 @@ public:
|
|||||||
/// \returns A type that refers to the dependent member type, or an error
|
/// \returns A type that refers to the dependent member type, or an error
|
||||||
/// type if such a reference is ill-formed.
|
/// type if such a reference is ill-formed.
|
||||||
virtual Type resolveSelfAssociatedType(Type selfTy,
|
virtual Type resolveSelfAssociatedType(Type selfTy,
|
||||||
DeclContext *DC,
|
|
||||||
AssociatedTypeDecl *assocType) = 0;
|
AssociatedTypeDecl *assocType) = 0;
|
||||||
|
|
||||||
/// Retrieve the type when referring to the given context.
|
/// Resolve the self type within the given context.
|
||||||
///
|
///
|
||||||
/// \param dc A context in which type checking occurs, which must be a type
|
/// \param dc A context in which type checking occurs, which must be a type
|
||||||
/// context (i.e., nominal type or extension thereof).
|
/// context (i.e., nominal type or extension thereof).
|
||||||
///
|
///
|
||||||
/// \param wantSelf Do we want the type of the context itself (the
|
|
||||||
/// existential type, for protocols) or the type of 'self' inside the
|
|
||||||
/// context (the 'Self' generic parameter, for protocols). Has no effect
|
|
||||||
/// for concrete types.
|
|
||||||
///
|
|
||||||
/// \returns the type of context.
|
/// \returns the type of context.
|
||||||
virtual Type resolveTypeOfContext(DeclContext *dc, bool wantSelf=false) = 0;
|
virtual Type resolveTypeOfContext(DeclContext *dc) = 0;
|
||||||
|
|
||||||
/// Retrieve the type when referring to the given type declaration within
|
/// Retrieve the type when referring to the given type declaration within
|
||||||
/// its context.
|
/// its context.
|
||||||
@@ -116,10 +110,9 @@ public:
|
|||||||
ComponentIdentTypeRepr *ref);
|
ComponentIdentTypeRepr *ref);
|
||||||
|
|
||||||
virtual Type resolveSelfAssociatedType(Type selfTy,
|
virtual Type resolveSelfAssociatedType(Type selfTy,
|
||||||
DeclContext *DC,
|
|
||||||
AssociatedTypeDecl *assocType);
|
AssociatedTypeDecl *assocType);
|
||||||
|
|
||||||
virtual Type resolveTypeOfContext(DeclContext *dc, bool wantSelf=false);
|
virtual Type resolveTypeOfContext(DeclContext *dc);
|
||||||
|
|
||||||
virtual Type resolveTypeOfDecl(TypeDecl *decl);
|
virtual Type resolveTypeOfDecl(TypeDecl *decl);
|
||||||
|
|
||||||
@@ -149,10 +142,9 @@ public:
|
|||||||
ComponentIdentTypeRepr *ref);
|
ComponentIdentTypeRepr *ref);
|
||||||
|
|
||||||
virtual Type resolveSelfAssociatedType(Type selfTy,
|
virtual Type resolveSelfAssociatedType(Type selfTy,
|
||||||
DeclContext *DC,
|
|
||||||
AssociatedTypeDecl *assocType);
|
AssociatedTypeDecl *assocType);
|
||||||
|
|
||||||
virtual Type resolveTypeOfContext(DeclContext *dc, bool wantSelf=false);
|
virtual Type resolveTypeOfContext(DeclContext *dc);
|
||||||
|
|
||||||
virtual Type resolveTypeOfDecl(TypeDecl *decl);
|
virtual Type resolveTypeOfDecl(TypeDecl *decl);
|
||||||
|
|
||||||
@@ -182,10 +174,9 @@ public:
|
|||||||
ComponentIdentTypeRepr *ref);
|
ComponentIdentTypeRepr *ref);
|
||||||
|
|
||||||
virtual Type resolveSelfAssociatedType(Type selfTy,
|
virtual Type resolveSelfAssociatedType(Type selfTy,
|
||||||
DeclContext *DC,
|
|
||||||
AssociatedTypeDecl *assocType);
|
AssociatedTypeDecl *assocType);
|
||||||
|
|
||||||
virtual Type resolveTypeOfContext(DeclContext *dc, bool wantSelf=false);
|
virtual Type resolveTypeOfContext(DeclContext *dc);
|
||||||
|
|
||||||
virtual Type resolveTypeOfDecl(TypeDecl *decl);
|
virtual Type resolveTypeOfDecl(TypeDecl *decl);
|
||||||
|
|
||||||
|
|||||||
@@ -50,9 +50,7 @@ Type DependentGenericTypeResolver::resolveDependentMemberType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type DependentGenericTypeResolver::resolveSelfAssociatedType(
|
Type DependentGenericTypeResolver::resolveSelfAssociatedType(
|
||||||
Type selfTy,
|
Type selfTy, AssociatedTypeDecl *assocType) {
|
||||||
DeclContext *DC,
|
|
||||||
AssociatedTypeDecl *assocType) {
|
|
||||||
auto archetype = Builder.resolveArchetype(selfTy);
|
auto archetype = Builder.resolveArchetype(selfTy);
|
||||||
assert(archetype && "Bad generic context nesting?");
|
assert(archetype && "Bad generic context nesting?");
|
||||||
|
|
||||||
@@ -61,15 +59,8 @@ Type DependentGenericTypeResolver::resolveSelfAssociatedType(
|
|||||||
->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/true);
|
->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type getTypeOfContext(DeclContext *dc, bool wantSelf) {
|
Type DependentGenericTypeResolver::resolveTypeOfContext(DeclContext *dc) {
|
||||||
if (wantSelf)
|
|
||||||
return dc->getSelfInterfaceType();
|
return dc->getSelfInterfaceType();
|
||||||
return dc->getDeclaredInterfaceType();
|
|
||||||
}
|
|
||||||
|
|
||||||
Type DependentGenericTypeResolver::resolveTypeOfContext(DeclContext *dc,
|
|
||||||
bool wantSelf) {
|
|
||||||
return getTypeOfContext(dc, wantSelf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Type DependentGenericTypeResolver::resolveTypeOfDecl(TypeDecl *decl) {
|
Type DependentGenericTypeResolver::resolveTypeOfDecl(TypeDecl *decl) {
|
||||||
@@ -106,21 +97,20 @@ Type GenericTypeToArchetypeResolver::resolveDependentMemberType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type GenericTypeToArchetypeResolver::resolveSelfAssociatedType(
|
Type GenericTypeToArchetypeResolver::resolveSelfAssociatedType(
|
||||||
Type selfTy,
|
Type selfTy, AssociatedTypeDecl *assocType) {
|
||||||
DeclContext *DC,
|
|
||||||
AssociatedTypeDecl *assocType) {
|
|
||||||
llvm_unreachable("Dependent type after archetype substitution");
|
llvm_unreachable("Dependent type after archetype substitution");
|
||||||
}
|
}
|
||||||
|
|
||||||
Type GenericTypeToArchetypeResolver::resolveTypeOfContext(DeclContext *dc,
|
Type GenericTypeToArchetypeResolver::resolveTypeOfContext(DeclContext *dc) {
|
||||||
bool wantSelf) {
|
|
||||||
// FIXME: Fallback case.
|
// FIXME: Fallback case.
|
||||||
if (dc->isGenericContext() && !dc->isValidGenericContext())
|
if (!isa<ExtensionDecl>(dc) &&
|
||||||
return getTypeOfContext(dc, wantSelf);
|
dc->isGenericContext() &&
|
||||||
|
!dc->isValidGenericContext())
|
||||||
|
return dc->getSelfInterfaceType();
|
||||||
|
|
||||||
return ArchetypeBuilder::mapTypeIntoContext(
|
return ArchetypeBuilder::mapTypeIntoContext(
|
||||||
dc->getParentModule(), GenericEnv,
|
dc->getParentModule(), GenericEnv,
|
||||||
getTypeOfContext(dc, wantSelf));
|
dc->getSelfInterfaceType());
|
||||||
}
|
}
|
||||||
|
|
||||||
Type GenericTypeToArchetypeResolver::resolveTypeOfDecl(TypeDecl *decl) {
|
Type GenericTypeToArchetypeResolver::resolveTypeOfDecl(TypeDecl *decl) {
|
||||||
@@ -242,17 +232,15 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
|
|||||||
return ErrorType::get(TC.Context);
|
return ErrorType::get(TC.Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type CompleteGenericTypeResolver::resolveSelfAssociatedType(Type selfTy,
|
Type CompleteGenericTypeResolver::resolveSelfAssociatedType(
|
||||||
DeclContext *DC,
|
Type selfTy, AssociatedTypeDecl *assocType) {
|
||||||
AssociatedTypeDecl *assocType) {
|
|
||||||
return Builder.resolveArchetype(selfTy)->getRepresentative()
|
return Builder.resolveArchetype(selfTy)->getRepresentative()
|
||||||
->getNestedType(assocType->getName(), Builder)
|
->getNestedType(assocType->getName(), Builder)
|
||||||
->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/false);
|
->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type CompleteGenericTypeResolver::resolveTypeOfContext(DeclContext *dc,
|
Type CompleteGenericTypeResolver::resolveTypeOfContext(DeclContext *dc) {
|
||||||
bool wantSelf) {
|
return dc->getSelfInterfaceType();
|
||||||
return getTypeOfContext(dc, wantSelf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Type CompleteGenericTypeResolver::resolveTypeOfDecl(TypeDecl *decl) {
|
Type CompleteGenericTypeResolver::resolveTypeOfDecl(TypeDecl *decl) {
|
||||||
|
|||||||
@@ -194,6 +194,125 @@ void TypeChecker::forceExternalDeclMembers(NominalTypeDecl *nominalDecl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Walk up through the type scopes to find the context containing the type
|
||||||
|
// being resolved.
|
||||||
|
//
|
||||||
|
// FIXME: UnqualifiedLookup already has this information; it needs to be
|
||||||
|
// plumbed through.
|
||||||
|
static std::tuple<DeclContext *, const NominalTypeDecl *, bool>
|
||||||
|
findDeclContextForType(TypeChecker &TC,
|
||||||
|
TypeDecl *typeDecl,
|
||||||
|
DeclContext *fromDC,
|
||||||
|
TypeResolutionOptions options) {
|
||||||
|
|
||||||
|
auto ownerDC = typeDecl->getDeclContext();
|
||||||
|
|
||||||
|
// If the type is declared at the top level, there's nothing we can learn from
|
||||||
|
// walking our parent contexts.
|
||||||
|
if (ownerDC->isModuleScopeContext())
|
||||||
|
return std::make_tuple(ownerDC, nullptr, true);
|
||||||
|
|
||||||
|
// Workaround for issue where generic typealias generic parameters are
|
||||||
|
// looked up with the wrong 'fromDC'.
|
||||||
|
if (isa<TypeAliasDecl>(ownerDC)) {
|
||||||
|
assert(isa<GenericTypeParamDecl>(typeDecl));
|
||||||
|
return std::make_tuple(ownerDC, nullptr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needsBaseType = (ownerDC->isTypeContext() &&
|
||||||
|
!isa<GenericTypeParamDecl>(typeDecl));
|
||||||
|
NominalTypeDecl *ownerNominal = nullptr;
|
||||||
|
if (needsBaseType) {
|
||||||
|
ownerNominal = ownerDC->getAsNominalTypeOrNominalTypeExtensionContext();
|
||||||
|
|
||||||
|
// We might have an invalid extension that didn't resolve.
|
||||||
|
if (ownerNominal == nullptr)
|
||||||
|
return std::make_tuple(nullptr, nullptr, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto parentDC = fromDC; !parentDC->isModuleContext();
|
||||||
|
parentDC = parentDC->getParent()) {
|
||||||
|
|
||||||
|
// If we're not computing a base type, we just have to check for
|
||||||
|
// containment in one of our parent contexts.
|
||||||
|
if (!needsBaseType) {
|
||||||
|
if (ownerDC == parentDC)
|
||||||
|
return std::make_tuple(ownerDC, nullptr, true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the next steps we need our parentDC to be a type context
|
||||||
|
if (!parentDC->isTypeContext())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Search the type of this context and its supertypes (if its a
|
||||||
|
// class) or refined protocols (if its a protocol).
|
||||||
|
llvm::SmallPtrSet<const NominalTypeDecl *, 8> visited;
|
||||||
|
llvm::SmallVector<const NominalTypeDecl *, 8> stack;
|
||||||
|
|
||||||
|
// Start with the type of the current context.
|
||||||
|
auto fromNominal = parentDC->getAsNominalTypeOrNominalTypeExtensionContext();
|
||||||
|
if (!fromNominal)
|
||||||
|
return std::make_tuple(nullptr, nullptr, false);
|
||||||
|
|
||||||
|
// Break circularity.
|
||||||
|
auto pushDecl = [&](const NominalTypeDecl *nominal) -> void {
|
||||||
|
if (visited.insert(nominal).second)
|
||||||
|
stack.push_back(nominal);
|
||||||
|
};
|
||||||
|
pushDecl(fromNominal);
|
||||||
|
|
||||||
|
// If we are in a protocol extension there might be other type aliases and
|
||||||
|
// nominal types brought into the context through requirements on Self,
|
||||||
|
// for example:
|
||||||
|
//
|
||||||
|
// extension MyProtocol where Self : YourProtocol { ... }
|
||||||
|
if (parentDC->getAsProtocolExtensionContext()) {
|
||||||
|
auto ED = cast<ExtensionDecl>(parentDC);
|
||||||
|
if (auto genericSig = ED->getGenericSignature()) {
|
||||||
|
for (auto req : genericSig->getRequirements()) {
|
||||||
|
if (req.getKind() == RequirementKind::Conformance ||
|
||||||
|
req.getKind() == RequirementKind::Superclass) {
|
||||||
|
if (req.getFirstType()->isEqual(ED->getSelfInterfaceType()))
|
||||||
|
if (auto *nominal = req.getSecondType()->getAnyNominal())
|
||||||
|
pushDecl(nominal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!stack.empty()) {
|
||||||
|
auto parentNominal = stack.back();
|
||||||
|
|
||||||
|
stack.pop_back();
|
||||||
|
|
||||||
|
// Check if we found the right context.
|
||||||
|
if (parentNominal == ownerNominal)
|
||||||
|
return std::make_tuple(parentDC, parentNominal, true);
|
||||||
|
|
||||||
|
// If not, walk into the superclass and inherited protocols, if any.
|
||||||
|
if (auto *protoDecl = dyn_cast<ProtocolDecl>(parentNominal)) {
|
||||||
|
for (auto *refined : protoDecl->getInheritedProtocols(&TC))
|
||||||
|
pushDecl(refined);
|
||||||
|
} else {
|
||||||
|
if (auto *classDecl = dyn_cast<ClassDecl>(parentNominal))
|
||||||
|
if (auto superclassTy = classDecl->getSuperclass())
|
||||||
|
if (auto superclassDecl = superclassTy->getClassOrBoundGenericClass())
|
||||||
|
pushDecl(superclassDecl);
|
||||||
|
if (!options.contains(TR_InheritanceClause)) {
|
||||||
|
// FIXME: wrong nominal decl
|
||||||
|
for (auto conforms : fromNominal->getAllProtocols()) {
|
||||||
|
pushDecl(conforms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false && "Should have found context by now");
|
||||||
|
return std::make_tuple(nullptr, nullptr, false);
|
||||||
|
}
|
||||||
|
|
||||||
Type TypeChecker::resolveTypeInContext(
|
Type TypeChecker::resolveTypeInContext(
|
||||||
TypeDecl *typeDecl,
|
TypeDecl *typeDecl,
|
||||||
DeclContext *fromDC,
|
DeclContext *fromDC,
|
||||||
@@ -210,6 +329,35 @@ Type TypeChecker::resolveTypeInContext(
|
|||||||
(*unsatisfiedDependency)(requestResolveTypeDecl(typeDecl)))
|
(*unsatisfiedDependency)(requestResolveTypeDecl(typeDecl)))
|
||||||
return Type();
|
return Type();
|
||||||
|
|
||||||
|
// FIXME: foundDC and foundNominal should come from UnqualifiedLookup
|
||||||
|
DeclContext *foundDC;
|
||||||
|
const NominalTypeDecl *foundNominal;
|
||||||
|
bool valid;
|
||||||
|
std::tie(foundDC, foundNominal, valid) =
|
||||||
|
findDeclContextForType(*this, typeDecl, fromDC, options);
|
||||||
|
|
||||||
|
if (!valid)
|
||||||
|
return ErrorType::get(Context);
|
||||||
|
|
||||||
|
assert(foundDC && "Should have found DeclContext by now");
|
||||||
|
|
||||||
|
// If we are referring to a type within its own context, and we have either
|
||||||
|
// a generic type with no generic arguments or a non-generic type, use the
|
||||||
|
// type within the context.
|
||||||
|
if (auto nominalType = dyn_cast<NominalTypeDecl>(typeDecl)) {
|
||||||
|
if (!isa<ProtocolDecl>(nominalType) &&
|
||||||
|
(!nominalType->getGenericParams() || !isSpecialized)) {
|
||||||
|
forceExternalDeclMembers(nominalType);
|
||||||
|
for (auto parentDC = fromDC;
|
||||||
|
!parentDC->isModuleScopeContext();
|
||||||
|
parentDC = parentDC->getParent()) {
|
||||||
|
if (parentDC->getAsNominalTypeOrNominalTypeExtensionContext() == nominalType)
|
||||||
|
return resolver->resolveTypeOfContext(parentDC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundNominal) {
|
||||||
// If we found a generic parameter, map to the archetype if there is one.
|
// If we found a generic parameter, map to the archetype if there is one.
|
||||||
if (auto genericParam = dyn_cast<GenericTypeParamDecl>(typeDecl)) {
|
if (auto genericParam = dyn_cast<GenericTypeParamDecl>(typeDecl)) {
|
||||||
return resolver->resolveGenericTypeParamType(
|
return resolver->resolveGenericTypeParamType(
|
||||||
@@ -217,52 +365,6 @@ Type TypeChecker::resolveTypeInContext(
|
|||||||
->castTo<GenericTypeParamType>());
|
->castTo<GenericTypeParamType>());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nominalType = dyn_cast<NominalTypeDecl>(typeDecl);
|
|
||||||
if (nominalType && (!nominalType->getGenericParams() || !isSpecialized)) {
|
|
||||||
forceExternalDeclMembers(nominalType);
|
|
||||||
} else {
|
|
||||||
nominalType = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Walk up through the type scopes to find the context containing the type
|
|
||||||
// being resolved.
|
|
||||||
auto ownerDC = typeDecl->getDeclContext();
|
|
||||||
bool nonTypeOwner = !ownerDC->isTypeContext();
|
|
||||||
auto ownerNominal = ownerDC->getAsNominalTypeOrNominalTypeExtensionContext();
|
|
||||||
|
|
||||||
// We might have an invalid extension that didn't resolve.
|
|
||||||
if (ownerNominal == nullptr && ownerDC->isExtensionContext()) {
|
|
||||||
assert(cast<ExtensionDecl>(ownerDC)->isInvalid());
|
|
||||||
return ErrorType::get(Context);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl);
|
|
||||||
assert((ownerNominal || nonTypeOwner) &&
|
|
||||||
"Owner must be a nominal type or a non type context");
|
|
||||||
|
|
||||||
// If true, we could not resolve some types, so we did not visit all
|
|
||||||
// relevant contexts.
|
|
||||||
bool incomplete = false;
|
|
||||||
|
|
||||||
for (auto parentDC = fromDC; !parentDC->isModuleContext();
|
|
||||||
parentDC = parentDC->getParent()) {
|
|
||||||
|
|
||||||
// If we are referring to a type within its own context, and we have either
|
|
||||||
// a generic type with no generic arguments or a non-generic type, use the
|
|
||||||
// type within the context.
|
|
||||||
if (nominalType) {
|
|
||||||
if (parentDC->getAsNominalTypeOrNominalTypeExtensionContext() == nominalType)
|
|
||||||
return resolver->resolveTypeOfContext(parentDC);
|
|
||||||
if (!parentDC->isModuleScopeContext() && !isa<TopLevelCodeDecl>(parentDC))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// If we didn't find a matching declaration, the iteration is restarted
|
|
||||||
// but we won't look anymore for the specific nominal type declaration
|
|
||||||
parentDC = fromDC;
|
|
||||||
nominalType = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nonTypeOwner) {
|
|
||||||
// If this is a typealias not in type context, we still need the
|
// If this is a typealias not in type context, we still need the
|
||||||
// interface type; the typealias might be in a function context, and
|
// interface type; the typealias might be in a function context, and
|
||||||
// its underlying type might reference outer generic parameters.
|
// its underlying type might reference outer generic parameters.
|
||||||
@@ -278,131 +380,46 @@ Type TypeChecker::resolveTypeInContext(
|
|||||||
return typeDecl->getDeclaredInterfaceType();
|
return typeDecl->getDeclaredInterfaceType();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the next steps we need our parentDC to be a type context
|
bool hasDependentType = typeDecl->getDeclaredInterfaceType()
|
||||||
if (!parentDC->isTypeContext())
|
->hasTypeParameter();
|
||||||
continue;
|
if (!hasDependentType)
|
||||||
|
return typeDecl->getDeclaredInterfaceType();
|
||||||
|
|
||||||
// Search the type of this context and its supertypes (if its a
|
// Now let's get the base type.
|
||||||
// class) or refined protocols (if its a protocol).
|
Type selfType;
|
||||||
llvm::SmallPtrSet<const NominalTypeDecl *, 8> visited;
|
|
||||||
llvm::SmallVector<Type, 8> stack;
|
|
||||||
|
|
||||||
// Start with the type of the current context.
|
// If we started from a protocol but found a member of a concrete type,
|
||||||
auto fromType = resolver->resolveTypeOfContext(parentDC);
|
// we have a protocol extension with a superclass constraint on 'Self'.
|
||||||
if (!fromType || fromType->hasError())
|
// Use the concrete type and not the protocol 'Self' type as the base
|
||||||
incomplete = true;
|
// of the substitution.
|
||||||
|
if (foundDC->getAsProtocolExtensionContext() &&
|
||||||
|
!isa<ProtocolDecl>(foundNominal))
|
||||||
|
selfType = foundNominal->getDeclaredType();
|
||||||
|
// Otherwise, just use the type of the context we're looking at.
|
||||||
else
|
else
|
||||||
stack.push_back(fromType);
|
selfType = resolver->resolveTypeOfContext(foundDC);
|
||||||
|
|
||||||
// If we are in a protocol extension there might be other type aliases and
|
if (!selfType || selfType->hasError())
|
||||||
// nominal types brought into the context through requirements on Self,
|
|
||||||
// for example:
|
|
||||||
//
|
|
||||||
// extension MyProtocol where Self : YourProtocol { ... }
|
|
||||||
if (parentDC->getAsProtocolExtensionContext()) {
|
|
||||||
auto ED = cast<ExtensionDecl>(parentDC);
|
|
||||||
if (auto genericSig = ED->getGenericSignature()) {
|
|
||||||
for (auto req : genericSig->getRequirements()) {
|
|
||||||
if (req.getKind() == RequirementKind::Conformance ||
|
|
||||||
req.getKind() == RequirementKind::Superclass) {
|
|
||||||
if (req.getFirstType()->isEqual(ED->getSelfInterfaceType()))
|
|
||||||
stack.push_back(req.getSecondType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!stack.empty()) {
|
|
||||||
auto fromType = stack.back();
|
|
||||||
auto *fromProto = parentDC->getAsProtocolOrProtocolExtensionContext();
|
|
||||||
|
|
||||||
stack.pop_back();
|
|
||||||
|
|
||||||
// If we hit circularity, we will diagnose at some point in typeCheckDecl().
|
|
||||||
// However we have to explicitly guard against that here because we get
|
|
||||||
// called as part of validateDecl().
|
|
||||||
if (!visited.insert(fromType->getAnyNominal()).second)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Handle this case:
|
|
||||||
// - Current context: concrete type
|
|
||||||
// - Nested type: associated type
|
|
||||||
// - Nested type's context: protocol or protocol extension
|
|
||||||
//
|
|
||||||
if (!fromProto &&
|
|
||||||
ownerNominal->getAsProtocolOrProtocolExtensionContext()) {
|
|
||||||
Optional<ProtocolConformanceRef> conformance;
|
|
||||||
|
|
||||||
// If the conformance check failed, the associated type is for a
|
|
||||||
// conformance of an outer context.
|
|
||||||
if (!options.contains(TR_InheritanceClause) &&
|
|
||||||
(conformance = conformsToProtocol(
|
|
||||||
fromType,
|
|
||||||
cast<ProtocolDecl>(ownerNominal),
|
|
||||||
parentDC, ConformanceCheckFlags::Used)) &&
|
|
||||||
conformance->isConcrete()) {
|
|
||||||
if (assocType) {
|
|
||||||
return conformance->getConcrete()->getTypeWitness(assocType, this)
|
|
||||||
.getReplacement();
|
|
||||||
}
|
|
||||||
|
|
||||||
return substMemberTypeWithBase(parentDC->getParentModule(), typeDecl,
|
|
||||||
fromType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle these cases:
|
|
||||||
// - Current context: concrete type
|
|
||||||
// - Nested type: concrete type or type alias
|
|
||||||
// - Nested type's context: concrete type
|
|
||||||
//
|
|
||||||
// - Current context: protocol or protocol extension
|
|
||||||
// - Nested type: type alias
|
|
||||||
// - Nested type's context: protocol or protocol extension
|
|
||||||
//
|
|
||||||
// Note: this is not supported yet, FIXME:
|
|
||||||
// - Current context: concrete type
|
|
||||||
// - Nested type: type alias
|
|
||||||
// - Nested type's context: protocol or protocol extension
|
|
||||||
//
|
|
||||||
if (fromType->getAnyNominal() == ownerNominal) {
|
|
||||||
if (fromProto &&
|
|
||||||
ownerNominal->getAsProtocolOrProtocolExtensionContext()) {
|
|
||||||
// If we are looking up an associated type or a protocol's type alias
|
|
||||||
// from a protocol or protocol extension, use the archetype for 'Self'
|
|
||||||
// instead of the existential type.
|
|
||||||
assert(fromType->is<ProtocolType>());
|
|
||||||
|
|
||||||
auto selfType = parentDC->getSelfInterfaceType();
|
|
||||||
if (!selfType)
|
|
||||||
return ErrorType::get(Context);
|
return ErrorType::get(Context);
|
||||||
fromType = resolver->resolveGenericTypeParamType(
|
|
||||||
selfType->castTo<GenericTypeParamType>());
|
|
||||||
|
|
||||||
if (assocType) {
|
// If we started from a protocol and found an associated type member
|
||||||
|
// of a (possibly inherited) protocol, resolve it via the resolver.
|
||||||
|
if (auto *assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) {
|
||||||
// Odd special case, ask Doug to explain it over pizza one day
|
// Odd special case, ask Doug to explain it over pizza one day
|
||||||
if (fromType->isTypeParameter())
|
if (selfType->isTypeParameter())
|
||||||
return resolver->resolveSelfAssociatedType(
|
return resolver->resolveSelfAssociatedType(
|
||||||
fromType, parentDC, assocType);
|
selfType, assocType);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return substMemberTypeWithBase(parentDC->getParentModule(), typeDecl,
|
// For type members of a base class, make sure we use the right
|
||||||
fromType);
|
// derived class as the parent type.
|
||||||
}
|
if (auto *ownerClass = typeDecl->getDeclContext()
|
||||||
|
->getAsClassOrClassExtensionContext())
|
||||||
|
selfType = selfType->getSuperclassForDecl(ownerClass, this);
|
||||||
|
|
||||||
if (auto superclassTy = getSuperClassOf(fromType))
|
// Finally, substitute the base type into the member type.
|
||||||
stack.push_back(superclassTy);
|
return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl,
|
||||||
else if (auto protoTy = fromType->getAs<ProtocolType>()) {
|
selfType);
|
||||||
for (auto *proto : protoTy->getDecl()->getInheritedProtocols(this))
|
|
||||||
if (auto refinedTy = proto->getDeclaredInterfaceType())
|
|
||||||
stack.push_back(refinedTy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(incomplete && "Should have found type by now");
|
|
||||||
return ErrorType::get(Context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function checks if a bound generic type is UnsafePointer<Void> or
|
/// This function checks if a bound generic type is UnsafePointer<Void> or
|
||||||
@@ -699,17 +716,6 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc,
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the nearest enclosing nominal type context.
|
|
||||||
static NominalTypeDecl *getEnclosingNominalContext(DeclContext *dc) {
|
|
||||||
while (dc->isLocalContext())
|
|
||||||
dc = dc->getParent();
|
|
||||||
|
|
||||||
if (auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext())
|
|
||||||
return nominal;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Diagnose a reference to an unknown type.
|
/// Diagnose a reference to an unknown type.
|
||||||
///
|
///
|
||||||
/// This routine diagnoses a reference to an unknown type, and
|
/// This routine diagnoses a reference to an unknown type, and
|
||||||
@@ -732,14 +738,15 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc,
|
|||||||
if (parentType.isNull()) {
|
if (parentType.isNull()) {
|
||||||
// Attempt to refer to 'Self' within a non-protocol nominal
|
// Attempt to refer to 'Self' within a non-protocol nominal
|
||||||
// type. Fix this by replacing 'Self' with the nominal type name.
|
// type. Fix this by replacing 'Self' with the nominal type name.
|
||||||
|
DeclContext *nominalDC = nullptr;
|
||||||
NominalTypeDecl *nominal = nullptr;
|
NominalTypeDecl *nominal = nullptr;
|
||||||
if (comp->getIdentifier() == tc.Context.Id_Self &&
|
if (comp->getIdentifier() == tc.Context.Id_Self &&
|
||||||
!isa<GenericIdentTypeRepr>(comp) &&
|
!isa<GenericIdentTypeRepr>(comp) &&
|
||||||
(nominal = getEnclosingNominalContext(dc))) {
|
(nominalDC = dc->getInnermostTypeContext()) &&
|
||||||
|
(nominal = nominalDC->getAsNominalTypeOrNominalTypeExtensionContext())) {
|
||||||
// Retrieve the nominal type and resolve it within this context.
|
// Retrieve the nominal type and resolve it within this context.
|
||||||
assert(!isa<ProtocolDecl>(nominal) && "Cannot be a protocol");
|
assert(!isa<ProtocolDecl>(nominal) && "Cannot be a protocol");
|
||||||
auto type = resolveTypeDecl(tc, nominal, comp->getIdLoc(), dc, nullptr,
|
auto type = resolver->resolveTypeOfContext(dc->getInnermostTypeContext());
|
||||||
options, resolver, unsatisfiedDependency);
|
|
||||||
if (type->hasError())
|
if (type->hasError())
|
||||||
return type;
|
return type;
|
||||||
|
|
||||||
@@ -926,8 +933,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC,
|
|||||||
// The issue is though that ComponentIdentTypeRepr only accepts a ValueDecl
|
// The issue is though that ComponentIdentTypeRepr only accepts a ValueDecl
|
||||||
// while the 'Self' type is more than just a reference to a TypeDecl.
|
// while the 'Self' type is more than just a reference to a TypeDecl.
|
||||||
|
|
||||||
auto selfType = resolver->resolveTypeOfContext(func->getDeclContext(),
|
auto selfType = resolver->resolveTypeOfContext(func->getDeclContext());
|
||||||
/*wantSelf=*/true);
|
|
||||||
return DynamicSelfType::get(selfType, TC.Context);
|
return DynamicSelfType::get(selfType, TC.Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s
|
|
||||||
// REQUIRES: asserts
|
|
||||||
func<{#^A^#protocol A{func<struct B
|
|
||||||
struct d<T where B:T>:A
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s
|
|
||||||
// REQUIRES: asserts
|
|
||||||
protocol c{#^A^#class B<d,g:T>:c
|
|
||||||
class T
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// RUN: %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s
|
||||||
|
func<{#^A^#protocol A{func<struct B
|
||||||
|
struct d<T where B:T>:A
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// RUN: %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s
|
||||||
|
protocol c{#^A^#class B<d,g:T>:c
|
||||||
|
class T
|
||||||
@@ -5,6 +5,6 @@
|
|||||||
// See https://swift.org/LICENSE.txt for license information
|
// See https://swift.org/LICENSE.txt for license information
|
||||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
|
||||||
// RUN: not --crash %target-swift-frontend %s -typecheck
|
// RUN: not %target-swift-frontend %s -typecheck
|
||||||
// REQUIRES: asserts
|
// REQUIRES: asserts
|
||||||
{protocol a{protocol b>class B<g:b>:a{func d:e}typealias e
|
{protocol a{protocol b>class B<g:b>:a{func d:e}typealias e
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
// See https://swift.org/LICENSE.txt for license information
|
// See https://swift.org/LICENSE.txt for license information
|
||||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
|
||||||
// RUN: not --crash %target-swift-frontend %s -typecheck
|
// RUN: not %target-swift-frontend %s -typecheck
|
||||||
// REQUIRES: asserts
|
// REQUIRES: asserts
|
||||||
{
|
{
|
||||||
protocol C{class B
|
protocol C{class B
|
||||||
@@ -5,6 +5,6 @@
|
|||||||
// See https://swift.org/LICENSE.txt for license information
|
// See https://swift.org/LICENSE.txt for license information
|
||||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
|
||||||
// RUN: not --crash %target-swift-frontend %s -emit-ir
|
// RUN: not %target-swift-frontend %s -emit-ir
|
||||||
// REQUIRES: asserts
|
// REQUIRES: asserts
|
||||||
{protocol A{class B{}struct Q<f,g where B:T>:A
|
{protocol A{class B{}struct Q<f,g where B:T>:A
|
||||||
Reference in New Issue
Block a user