mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
17
test/Inputs/forward_extension_reference.swift
Normal file
17
test/Inputs/forward_extension_reference.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
22
test/decl/ext/forward_references.swift
Normal file
22
test/decl/ext/forward_references.swift
Normal 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}
|
||||
}
|
||||
Reference in New Issue
Block a user