When attempting to obtain the context type of a type extension, we were never taking into account the fact that the extended type could be potentially be unbound.

(This could occur, for instance, via a forward reference to a member defined in an extension to a generic type.)  This problem has been popping up a lot lately, and
was making some of the recent runtime work difficult.  (rdar://problem/16481483)

Swift SVN r15805
This commit is contained in:
Joe Pamer
2014-04-02 16:48:14 +00:00
parent f6e87dec54
commit 31bab38eb4
5 changed files with 69 additions and 17 deletions

View File

@@ -28,7 +28,9 @@ namespace swift {
class AbstractFunctionDecl;
class ASTContext;
class ASTWalker;
class CanType;
class DeclContext;
class ExtensionDecl;
class GenericParamList;
class LazyResolver;
class GenericSignature;
@@ -115,6 +117,10 @@ public:
DeclContextKind getContextKind() const {
return ParentAndKind.getInt();
}
/// \brief Obtain the canonical type from a type extension declaration,
/// binding any unbound generic types if necessary.
static CanType getExtendedType(ExtensionDecl *ED);
/// Determines whether this context is itself a local scope in a
/// code block. A context that appears in such a scope, like a

View File

@@ -10,14 +10,27 @@
//
//===----------------------------------------------------------------------===//
#include "swift/AST/DeclContext.h"
#include "swift/AST/AST.h"
#include "swift/AST/DeclContext.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Types.h"
#include "swift/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace swift;
CanType DeclContext::getExtendedType(ExtensionDecl *ED) {
CanType ExtendedTy = ED->getExtendedType()->getCanonicalType();
// FIXME: we should require generic parameter clauses here
if (auto unbound = dyn_cast<UnboundGenericType>(ExtendedTy)) {
auto boundType = unbound->getDecl()->getDeclaredTypeInContext();
ED->getExtendedTypeLoc().setType(boundType, true);
ExtendedTy = boundType->getCanonicalType();
}
return ExtendedTy;
}
// Only allow allocation of DeclContext using the allocator in ASTContext.
void *DeclContext::operator new(size_t Bytes, ASTContext &C,
unsigned Alignment) {
@@ -39,9 +52,15 @@ Type DeclContext::getDeclaredTypeOfContext() const {
return Type();
case DeclContextKind::ExtensionDecl: {
auto type = cast<ExtensionDecl>(this)->getExtendedType();
auto ED = cast<ExtensionDecl>(this);
auto type = ED->getExtendedType();
if (auto ND = type->getNominalOrBoundGenericNominal())
return ND->getDeclaredType();
if (dyn_cast<UnboundGenericType>(type.getPointer())) {
return getExtendedType(const_cast<ExtensionDecl*>(ED));
}
return Type();
}
@@ -61,7 +80,7 @@ Type DeclContext::getDeclaredTypeInContext() {
return Type();
case DeclContextKind::ExtensionDecl:
return cast<ExtensionDecl>(this)->getExtendedType();
return getExtendedType(cast<ExtensionDecl>(this));
case DeclContextKind::NominalTypeDecl:
return cast<NominalTypeDecl>(this)->getDeclaredTypeInContext();

View File

@@ -605,18 +605,6 @@ static void setBoundVarsTypeError(Pattern *pattern, ASTContext &ctx) {
});
}
static CanType getExtendedType(ExtensionDecl *ED) {
CanType ExtendedTy = ED->getExtendedType()->getCanonicalType();
// FIXME: we should require generic parameter clauses here
if (auto unbound = dyn_cast<UnboundGenericType>(ExtendedTy)) {
auto boundType = unbound->getDecl()->getDeclaredTypeInContext();
ED->getExtendedTypeLoc().setType(boundType, true);
ExtendedTy = boundType->getCanonicalType();
}
return ExtendedTy;
}
/// Create a fresh archetype builder.
/// FIXME: Duplicated with TypeCheckGeneric.cpp; this one should go away.
ArchetypeBuilder TypeChecker::createArchetypeBuilder(Module *mod) {
@@ -3359,7 +3347,7 @@ public:
}
if (!IsSecondPass) {
CanType ExtendedTy = getExtendedType(ED);
CanType ExtendedTy = DeclContext::getExtendedType(ED);
if (!isa<EnumType>(ExtendedTy) &&
!isa<StructType>(ExtendedTy) &&
@@ -5003,7 +4991,7 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
// Only Struct and Enum extensions can be transparent.
} else if (ED) {
CanType ExtendedTy = getExtendedType(ED);
CanType ExtendedTy = DeclContext::getExtendedType(ED);
if (!isa<StructType>(ExtendedTy) && !isa<EnumType>(ExtendedTy)) {
TC.diagnose(Attrs.getLoc(AK_transparent),
diag::transparent_on_invalid_extension);

View File

@@ -0,0 +1,17 @@
extension Foo : Bar {
var count: Int {
get {
var x = Int(_countAndFlags >> 1)
var y = Int(_countAndFlags >> 1)
var z = _countAndFlags >> 1
return x
}
set {
let growth = newValue - count
if growth == 0 {
return
}
_countAndFlags = (UInt(newValue) << 1) | (_countAndFlags & 1)
}
}
}

View File

@@ -0,0 +1,22 @@
// RUN: %swift -primary-file %s %S/../../Inputs/forward_extension_reference.swift -target x86_64-apple-darwin10 -emit-ir -g -module-name fref
// RUN: %swift %S/../../Inputs/forward_extension_reference.swift -primary-file %s -target x86_64-apple-darwin10 -emit-ir -g -module-name fref
struct Foo<T> {
func foo(t: T) -> T {
return t
}
var _countAndFlags: UInt = 0
func gar() -> Int {
return count
}
}
func goo<T>(f: Foo<T>) {
var x = f.count
}
protocol Bar {
var count: Int {get set}
}