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.
|
||||
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 baseRange The source range covering the base type.
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
SourceRange baseRange,
|
||||
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.
|
||||
///
|
||||
/// \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
|
||||
/// type if such a reference is ill-formed.
|
||||
virtual Type resolveSelfAssociatedType(Type selfTy,
|
||||
DeclContext *DC,
|
||||
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
|
||||
/// 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.
|
||||
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
|
||||
/// its context.
|
||||
@@ -116,10 +110,9 @@ public:
|
||||
ComponentIdentTypeRepr *ref);
|
||||
|
||||
virtual Type resolveSelfAssociatedType(Type selfTy,
|
||||
DeclContext *DC,
|
||||
AssociatedTypeDecl *assocType);
|
||||
|
||||
virtual Type resolveTypeOfContext(DeclContext *dc, bool wantSelf=false);
|
||||
virtual Type resolveTypeOfContext(DeclContext *dc);
|
||||
|
||||
virtual Type resolveTypeOfDecl(TypeDecl *decl);
|
||||
|
||||
@@ -149,10 +142,9 @@ public:
|
||||
ComponentIdentTypeRepr *ref);
|
||||
|
||||
virtual Type resolveSelfAssociatedType(Type selfTy,
|
||||
DeclContext *DC,
|
||||
AssociatedTypeDecl *assocType);
|
||||
|
||||
virtual Type resolveTypeOfContext(DeclContext *dc, bool wantSelf=false);
|
||||
virtual Type resolveTypeOfContext(DeclContext *dc);
|
||||
|
||||
virtual Type resolveTypeOfDecl(TypeDecl *decl);
|
||||
|
||||
@@ -182,10 +174,9 @@ public:
|
||||
ComponentIdentTypeRepr *ref);
|
||||
|
||||
virtual Type resolveSelfAssociatedType(Type selfTy,
|
||||
DeclContext *DC,
|
||||
AssociatedTypeDecl *assocType);
|
||||
|
||||
virtual Type resolveTypeOfContext(DeclContext *dc, bool wantSelf=false);
|
||||
virtual Type resolveTypeOfContext(DeclContext *dc);
|
||||
|
||||
virtual Type resolveTypeOfDecl(TypeDecl *decl);
|
||||
|
||||
|
||||
@@ -50,9 +50,7 @@ Type DependentGenericTypeResolver::resolveDependentMemberType(
|
||||
}
|
||||
|
||||
Type DependentGenericTypeResolver::resolveSelfAssociatedType(
|
||||
Type selfTy,
|
||||
DeclContext *DC,
|
||||
AssociatedTypeDecl *assocType) {
|
||||
Type selfTy, AssociatedTypeDecl *assocType) {
|
||||
auto archetype = Builder.resolveArchetype(selfTy);
|
||||
assert(archetype && "Bad generic context nesting?");
|
||||
|
||||
@@ -61,15 +59,8 @@ Type DependentGenericTypeResolver::resolveSelfAssociatedType(
|
||||
->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/true);
|
||||
}
|
||||
|
||||
static Type getTypeOfContext(DeclContext *dc, bool wantSelf) {
|
||||
if (wantSelf)
|
||||
Type DependentGenericTypeResolver::resolveTypeOfContext(DeclContext *dc) {
|
||||
return dc->getSelfInterfaceType();
|
||||
return dc->getDeclaredInterfaceType();
|
||||
}
|
||||
|
||||
Type DependentGenericTypeResolver::resolveTypeOfContext(DeclContext *dc,
|
||||
bool wantSelf) {
|
||||
return getTypeOfContext(dc, wantSelf);
|
||||
}
|
||||
|
||||
Type DependentGenericTypeResolver::resolveTypeOfDecl(TypeDecl *decl) {
|
||||
@@ -106,21 +97,20 @@ Type GenericTypeToArchetypeResolver::resolveDependentMemberType(
|
||||
}
|
||||
|
||||
Type GenericTypeToArchetypeResolver::resolveSelfAssociatedType(
|
||||
Type selfTy,
|
||||
DeclContext *DC,
|
||||
AssociatedTypeDecl *assocType) {
|
||||
Type selfTy, AssociatedTypeDecl *assocType) {
|
||||
llvm_unreachable("Dependent type after archetype substitution");
|
||||
}
|
||||
|
||||
Type GenericTypeToArchetypeResolver::resolveTypeOfContext(DeclContext *dc,
|
||||
bool wantSelf) {
|
||||
Type GenericTypeToArchetypeResolver::resolveTypeOfContext(DeclContext *dc) {
|
||||
// FIXME: Fallback case.
|
||||
if (dc->isGenericContext() && !dc->isValidGenericContext())
|
||||
return getTypeOfContext(dc, wantSelf);
|
||||
if (!isa<ExtensionDecl>(dc) &&
|
||||
dc->isGenericContext() &&
|
||||
!dc->isValidGenericContext())
|
||||
return dc->getSelfInterfaceType();
|
||||
|
||||
return ArchetypeBuilder::mapTypeIntoContext(
|
||||
dc->getParentModule(), GenericEnv,
|
||||
getTypeOfContext(dc, wantSelf));
|
||||
dc->getSelfInterfaceType());
|
||||
}
|
||||
|
||||
Type GenericTypeToArchetypeResolver::resolveTypeOfDecl(TypeDecl *decl) {
|
||||
@@ -242,17 +232,15 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
|
||||
return ErrorType::get(TC.Context);
|
||||
}
|
||||
|
||||
Type CompleteGenericTypeResolver::resolveSelfAssociatedType(Type selfTy,
|
||||
DeclContext *DC,
|
||||
AssociatedTypeDecl *assocType) {
|
||||
Type CompleteGenericTypeResolver::resolveSelfAssociatedType(
|
||||
Type selfTy, AssociatedTypeDecl *assocType) {
|
||||
return Builder.resolveArchetype(selfTy)->getRepresentative()
|
||||
->getNestedType(assocType->getName(), Builder)
|
||||
->getDependentType(/*FIXME: */{ }, /*allowUnresolved=*/false);
|
||||
}
|
||||
|
||||
Type CompleteGenericTypeResolver::resolveTypeOfContext(DeclContext *dc,
|
||||
bool wantSelf) {
|
||||
return getTypeOfContext(dc, wantSelf);
|
||||
Type CompleteGenericTypeResolver::resolveTypeOfContext(DeclContext *dc) {
|
||||
return dc->getSelfInterfaceType();
|
||||
}
|
||||
|
||||
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(
|
||||
TypeDecl *typeDecl,
|
||||
DeclContext *fromDC,
|
||||
@@ -210,6 +329,35 @@ Type TypeChecker::resolveTypeInContext(
|
||||
(*unsatisfiedDependency)(requestResolveTypeDecl(typeDecl)))
|
||||
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 (auto genericParam = dyn_cast<GenericTypeParamDecl>(typeDecl)) {
|
||||
return resolver->resolveGenericTypeParamType(
|
||||
@@ -217,52 +365,6 @@ Type TypeChecker::resolveTypeInContext(
|
||||
->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
|
||||
// interface type; the typealias might be in a function context, and
|
||||
// its underlying type might reference outer generic parameters.
|
||||
@@ -278,131 +380,46 @@ Type TypeChecker::resolveTypeInContext(
|
||||
return typeDecl->getDeclaredInterfaceType();
|
||||
}
|
||||
|
||||
// For the next steps we need our parentDC to be a type context
|
||||
if (!parentDC->isTypeContext())
|
||||
continue;
|
||||
bool hasDependentType = typeDecl->getDeclaredInterfaceType()
|
||||
->hasTypeParameter();
|
||||
if (!hasDependentType)
|
||||
return typeDecl->getDeclaredInterfaceType();
|
||||
|
||||
// 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<Type, 8> stack;
|
||||
// Now let's get the base type.
|
||||
Type selfType;
|
||||
|
||||
// Start with the type of the current context.
|
||||
auto fromType = resolver->resolveTypeOfContext(parentDC);
|
||||
if (!fromType || fromType->hasError())
|
||||
incomplete = true;
|
||||
// If we started from a protocol but found a member of a concrete type,
|
||||
// we have a protocol extension with a superclass constraint on 'Self'.
|
||||
// Use the concrete type and not the protocol 'Self' type as the base
|
||||
// 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
|
||||
stack.push_back(fromType);
|
||||
selfType = resolver->resolveTypeOfContext(foundDC);
|
||||
|
||||
// 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()))
|
||||
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)
|
||||
if (!selfType || selfType->hasError())
|
||||
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
|
||||
if (fromType->isTypeParameter())
|
||||
if (selfType->isTypeParameter())
|
||||
return resolver->resolveSelfAssociatedType(
|
||||
fromType, parentDC, assocType);
|
||||
}
|
||||
selfType, assocType);
|
||||
}
|
||||
|
||||
return substMemberTypeWithBase(parentDC->getParentModule(), typeDecl,
|
||||
fromType);
|
||||
}
|
||||
// For type members of a base class, make sure we use the right
|
||||
// derived class as the parent type.
|
||||
if (auto *ownerClass = typeDecl->getDeclContext()
|
||||
->getAsClassOrClassExtensionContext())
|
||||
selfType = selfType->getSuperclassForDecl(ownerClass, this);
|
||||
|
||||
if (auto superclassTy = getSuperClassOf(fromType))
|
||||
stack.push_back(superclassTy);
|
||||
else if (auto protoTy = fromType->getAs<ProtocolType>()) {
|
||||
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);
|
||||
// Finally, substitute the base type into the member type.
|
||||
return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl,
|
||||
selfType);
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// This routine diagnoses a reference to an unknown type, and
|
||||
@@ -732,14 +738,15 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc,
|
||||
if (parentType.isNull()) {
|
||||
// Attempt to refer to 'Self' within a non-protocol nominal
|
||||
// type. Fix this by replacing 'Self' with the nominal type name.
|
||||
DeclContext *nominalDC = nullptr;
|
||||
NominalTypeDecl *nominal = nullptr;
|
||||
if (comp->getIdentifier() == tc.Context.Id_Self &&
|
||||
!isa<GenericIdentTypeRepr>(comp) &&
|
||||
(nominal = getEnclosingNominalContext(dc))) {
|
||||
(nominalDC = dc->getInnermostTypeContext()) &&
|
||||
(nominal = nominalDC->getAsNominalTypeOrNominalTypeExtensionContext())) {
|
||||
// Retrieve the nominal type and resolve it within this context.
|
||||
assert(!isa<ProtocolDecl>(nominal) && "Cannot be a protocol");
|
||||
auto type = resolveTypeDecl(tc, nominal, comp->getIdLoc(), dc, nullptr,
|
||||
options, resolver, unsatisfiedDependency);
|
||||
auto type = resolver->resolveTypeOfContext(dc->getInnermostTypeContext());
|
||||
if (type->hasError())
|
||||
return type;
|
||||
|
||||
@@ -926,8 +933,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC,
|
||||
// The issue is though that ComponentIdentTypeRepr only accepts a ValueDecl
|
||||
// while the 'Self' type is more than just a reference to a TypeDecl.
|
||||
|
||||
auto selfType = resolver->resolveTypeOfContext(func->getDeclContext(),
|
||||
/*wantSelf=*/true);
|
||||
auto selfType = resolver->resolveTypeOfContext(func->getDeclContext());
|
||||
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/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
|
||||
{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/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
|
||||
{
|
||||
protocol C{class B
|
||||
@@ -5,6 +5,6 @@
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// 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
|
||||
{protocol A{class B{}struct Q<f,g where B:T>:A
|
||||
Reference in New Issue
Block a user