Skip to content

A few fixes for preCheckExpression(), and a cleanup #9787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/swift/AST/TypeAlignments.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace swift {
class Substitution;
class TypeVariableType;
class TypeBase;
class TypeDecl;
class ValueDecl;

/// We frequently use three tag bits on all of these types.
Expand Down Expand Up @@ -87,6 +88,7 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::AssociatedTypeDecl, swift::DeclAlignInBits)
LLVM_DECLARE_TYPE_ALIGNMENT(swift::GenericTypeParamDecl, swift::DeclAlignInBits)
LLVM_DECLARE_TYPE_ALIGNMENT(swift::OperatorDecl, swift::DeclAlignInBits)
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ProtocolDecl, swift::DeclAlignInBits)
LLVM_DECLARE_TYPE_ALIGNMENT(swift::TypeDecl, swift::DeclAlignInBits)
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ValueDecl, swift::DeclAlignInBits)
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ExtensionDecl, swift::DeclAlignInBits)

Expand Down
10 changes: 5 additions & 5 deletions include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace swift {
class DeclContext;
class GenericEnvironment;
class IdentTypeRepr;
class ValueDecl;
class TypeDecl;

enum class TypeReprKind : uint8_t {
#define TYPEREPR(ID, PARENT) ID,
Expand Down Expand Up @@ -243,7 +243,7 @@ class ComponentIdentTypeRepr : public IdentTypeRepr {
///
/// The initial parsed representation is always an identifier, and
/// name binding will resolve this to a specific declaration.
llvm::PointerUnion<Identifier, ValueDecl *> IdOrDecl;
llvm::PointerUnion<Identifier, TypeDecl *> IdOrDecl;

protected:
ComponentIdentTypeRepr(TypeReprKind K, SourceLoc Loc, Identifier Id)
Expand All @@ -258,11 +258,11 @@ class ComponentIdentTypeRepr : public IdentTypeRepr {
void overwriteIdentifier(Identifier newId) { IdOrDecl = newId; }

/// Return true if this has been name-bound already.
bool isBound() const { return IdOrDecl.is<ValueDecl *>(); }
bool isBound() const { return IdOrDecl.is<TypeDecl *>(); }

ValueDecl *getBoundDecl() const { return IdOrDecl.dyn_cast<ValueDecl*>(); }
TypeDecl *getBoundDecl() const { return IdOrDecl.dyn_cast<TypeDecl*>(); }

void setValue(ValueDecl *VD) { IdOrDecl = VD; }
void setValue(TypeDecl *TD) { IdOrDecl = TD; }

static bool classof(const TypeRepr *T) {
return T->getKind() == TypeReprKind::SimpleIdent ||
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/TypeRepr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Identifier ComponentIdentTypeRepr::getIdentifier() const {
if (IdOrDecl.is<Identifier>())
return IdOrDecl.get<Identifier>();

return IdOrDecl.get<ValueDecl *>()->getName();
return IdOrDecl.get<TypeDecl *>()->getName();
}

static void printTypeRepr(const TypeRepr *TyR, ASTPrinter &Printer,
Expand Down
4 changes: 2 additions & 2 deletions lib/Parse/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -775,8 +775,8 @@ namespace {
auto *T = dyn_cast_or_null<IdentTypeRepr>(Ty);
auto Comp = T->getComponentRange().front();
if (auto Entry = P.lookupInScope(Comp->getIdentifier()))
if (isa<TypeDecl>(Entry)) {
Comp->setValue(Entry);
if (auto *TD = dyn_cast<TypeDecl>(Entry)) {
Comp->setValue(TD);
return false;
}
return true;
Expand Down
12 changes: 8 additions & 4 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,8 +581,8 @@ ParserResult<TypeRepr> Parser::parseTypeIdentifier() {
// Lookup element #0 through our current scope chains in case it is some
// thing local (this returns null if nothing is found).
if (auto Entry = lookupInScope(ComponentsR[0]->getIdentifier()))
if (isa<TypeDecl>(Entry))
ComponentsR[0]->setValue(Entry);
if (auto *TD = dyn_cast<TypeDecl>(Entry))
ComponentsR[0]->setValue(TD);

ITR = IdentTypeRepr::create(Context, ComponentsR);
}
Expand Down Expand Up @@ -1136,9 +1136,13 @@ static bool isGenericTypeDisambiguatingToken(Parser &P) {
case tok::exclaim_postfix:
case tok::question_postfix:
return true;

case tok::oper_binary_unspaced:

case tok::oper_binary_spaced:
if (tok.getText() == "&")
return true;

LLVM_FALLTHROUGH;
case tok::oper_binary_unspaced:
case tok::oper_postfix:
// These might be '?' or '!' type modifiers.
return P.isOptionalToken(tok) || P.isImplicitlyUnwrappedOptionalToken(tok);
Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1324,7 +1324,8 @@ TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) {
return nullptr;
else
return nullptr;
}
} else
return nullptr;

// Add the rhs which is just a TypeExpr
auto *rhs = dyn_cast<TypeExpr>(binaryExpr->getArg()->getElement(1));
Expand Down
16 changes: 6 additions & 10 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1137,9 +1137,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC,

// If the component has already been bound to a declaration, handle
// that now.
if (ValueDecl *VD = comp->getBoundDecl()) {
auto *typeDecl = cast<TypeDecl>(VD);

if (auto *typeDecl = comp->getBoundDecl()) {
// Resolve the type declaration within this context.
return resolveTypeDecl(TC, typeDecl, comp->getIdLoc(), DC,
dyn_cast<GenericIdentTypeRepr>(comp), options,
Expand Down Expand Up @@ -1328,9 +1326,7 @@ static Type resolveNestedIdentTypeComponent(
}

// Phase 2: If a declaration has already been bound, use it.
if (ValueDecl *decl = comp->getBoundDecl()) {
auto *typeDecl = cast<TypeDecl>(decl);

if (auto *typeDecl = comp->getBoundDecl()) {
// Otherwise, simply substitute the parent type into the member.
auto memberType = TC.substMemberTypeWithBase(DC->getParentModule(),
typeDecl, parentTy);
Expand Down Expand Up @@ -1428,7 +1424,7 @@ static Type resolveNestedIdentTypeComponent(
}

memberType = ty;
member = cast_or_null<TypeDecl>(comp->getBoundDecl());
member = comp->getBoundDecl();
} else {
memberType = memberTypes.back().second;
member = memberTypes.back().first;
Expand Down Expand Up @@ -1530,7 +1526,7 @@ static bool diagnoseAvailability(IdentTypeRepr *IdType,
bool AllowPotentiallyUnavailableProtocol) {
auto componentRange = IdType->getComponentRange();
for (auto comp : componentRange) {
if (auto typeDecl = dyn_cast_or_null<TypeDecl>(comp->getBoundDecl())) {
if (auto *typeDecl = comp->getBoundDecl()) {
// In Swift 3, components other than the last one were not properly
// checked for availability.
// FIXME: We should try to downgrade these errors to warnings, not just
Expand Down Expand Up @@ -4053,13 +4049,13 @@ class UnsupportedProtocolVisitor
return;

auto comp = T->getComponentRange().back();
if (auto proto = dyn_cast_or_null<ProtocolDecl>(comp->getBoundDecl())) {
if (auto *proto = dyn_cast_or_null<ProtocolDecl>(comp->getBoundDecl())) {
if (!proto->existentialTypeSupported(&TC)) {
TC.diagnose(comp->getIdLoc(), diag::unsupported_existential_type,
proto->getName());
T->setInvalid();
}
} else if (auto alias = dyn_cast_or_null<TypeAliasDecl>(comp->getBoundDecl())) {
} else if (auto *alias = dyn_cast_or_null<TypeAliasDecl>(comp->getBoundDecl())) {
if (!alias->hasInterfaceType())
return;
auto type = Type(alias->getDeclaredInterfaceType()->getDesugaredType());
Expand Down
33 changes: 15 additions & 18 deletions test/Interpreter/subclass_existentials.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,28 +141,25 @@ protocol Q : class {}

var SubclassExistentialsTestSuite = TestSuite("SubclassExistentials")

// Note: we write ((A) & B) if A is generic to work around a limitation
// in preCheckExpression().

SubclassExistentialsTestSuite.test("Metadata instantiation") {
expectTrue(((Base<String>) & Base<String>).self == Base<String>.self)
expectTrue(((Base<String>) & Any).self == Base<String>.self)
expectTrue((Base<String> & Base<String>).self == Base<String>.self)
expectTrue((Base<String> & Any).self == Base<String>.self)

expectTrue(((Base<Int>) & Q).self == (Q & Base<Int>).self)
expectTrue((Base<Int> & Q).self == (Q & Base<Int>).self)

expectTrue(((Base<Int>) & P & Q).self == (P & (Base<Int>) & Q).self)
expectTrue((P & Q & (Base<Int>)).self == (Q & (Base<Int>) & P).self)
expectTrue((Base<Int> & P & Q).self == (P & Base<Int> & Q).self)
expectTrue((P & Q & Base<Int>).self == (Q & Base<Int> & P).self)

expectTrue((P & Q).self == (P & Q & AnyObject).self)
expectTrue((P & Q).self == (Q & P & AnyObject).self)
expectTrue(((Base<Int>) & Q).self == (Q & (Base<Int>) & AnyObject).self)
expectTrue((Base<Int> & Q).self == (Q & Base<Int> & AnyObject).self)

expectFalse((R & AnyObject).self == R.self)
}

SubclassExistentialsTestSuite.test("Metadata to string") {
expectEqual("Base<Int> & P", String(describing: ((Base<Int>) & P).self))
expectEqual("Base<Int> & P & Q", String(describing: ((Base<Int>) & P & Q).self))
expectEqual("Base<Int> & P", String(describing: (Base<Int> & P).self))
expectEqual("Base<Int> & P & Q", String(describing: (Base<Int> & P & Q).self))
}

SubclassExistentialsTestSuite.test("Call instance methods") {
Expand Down Expand Up @@ -360,31 +357,31 @@ func cast<T, U>(_ t: T, to: U.Type) -> U? {
SubclassExistentialsTestSuite.test("Dynamic downcast to subclass existential") {
do {
let baseInt: Base<Int> = Derived(x: 123, y: 321)
let derived = cast(baseInt, to: ((Base<Int>) & P).self)
let derived = cast(baseInt, to: (Base<Int> & P).self)

expectEqual(123, derived!.x)
expectEqual(321, derived!.y)
}

do {
let p: P = Derived(x: 123, y: 321)
let result = cast(p, to: ((Base<Int>) & P).self)
let result = cast(p, to: (Base<Int> & P).self)

expectEqual(123, result!.x)
expectEqual(321, result!.y)
}

do {
let r: R = Derived(x: 123, y: 321)
let result = cast(r, to: ((Base<Int>) & P).self)
let result = cast(r, to: (Base<Int> & P).self)

expectEqual(123, result!.x)
expectEqual(321, result!.y)
}

do {
let baseInt: Base<Int> = Derived(x: 123, y: 321)
let result = cast(baseInt, to: ((Base<Int>) & P).self)
let result = cast(baseInt, to: (Base<Int> & P).self)

expectEqual(123, result!.x)
expectEqual(321, result!.y)
Expand Down Expand Up @@ -445,19 +442,19 @@ SubclassExistentialsTestSuite.test("Failing dynamic downcast to subclass existen
do {
let baseInt: Base<Int> = Base<Int>(x: 123, y: 321)

expectNil(cast(baseInt, to: ((Base<Int>) & P).self))
expectNil(cast(baseInt, to: (Base<Int> & P).self))
}

do {
let r: R = Base<Int>(x: 123, y: 321)

expectNil(cast(r, to: ((Base<Int>) & P).self))
expectNil(cast(r, to: (Base<Int> & P).self))
}

do {
let conformsToP = ConformsToP(protocolInit: ())

expectNil(cast(conformsToP, to: ((Base<Int>) & P).self))
expectNil(cast(conformsToP, to: (Base<Int> & P).self))
}
}

Expand Down
10 changes: 10 additions & 0 deletions test/type/protocol_composition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,13 @@ struct S05<T> where T : P5? & P6 {} // expected-error {{inheritance from non-nam
struct S3124<T: protocol<P1, P3>> {} // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}} {{17-34=P1 & P3>}}
func f3124_1<U where U: protocol<P1, P3>>(x: U) {} // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}} {{25-42=P1 & P3>}} // expected-error {{'where' clause}}
func f3124_2<U : protocol<P1>>(x: U) {} // expected-warning {{'protocol<...>' composition syntax is deprecated and not needed here}} {{18-31=P1>}}

// Make sure we correctly form compositions in expression context
func takesP1AndP2(_: [AnyObject & P1 & P2]) {}

takesP1AndP2([AnyObject & P1 & P2]())
// takesP1AndP2([Swift.AnyObject & P1 & P2]()) // FIXME
// takesP1AndP2([AnyObject & protocol_composition.P1 & P2]()) // FIXME
// takesP1AndP2([AnyObject & P1 & protocol_composition.P2]()) // FIXME
takesP1AndP2([DoesNotExist & P1 & P2]()) // expected-error {{use of unresolved identifier 'DoesNotExist'}}
takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}}
7 changes: 7 additions & 0 deletions test/type/subclass_composition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -531,3 +531,10 @@ func staticMembers(
_ = m2.instanceProtocolMember // expected-error {{instance member 'instanceProtocolMember' cannot be used on type 'ClassWithStaticMember & ProtocolWithStaticMember'}}
_ = m2.instanceClassMember // expected-error {{instance member 'instanceClassMember' cannot be used on type 'ClassWithStaticMember & ProtocolWithStaticMember'}}
}

// Make sure we correctly form subclass existentials in expression context.
func takesBaseIntAndPArray(_: [Base<Int> & P2]) {}

func passesBaseIntAndPArray() {
takesBaseIntAndPArray([Base<Int> & P2]())
}