Skip to content

Fix printing of class-constrained protocols [4.0] #11786

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
14 changes: 0 additions & 14 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3489,9 +3489,6 @@ struct SelfReferenceKind {
class ProtocolDecl : public NominalTypeDecl {
SourceLoc ProtocolLoc;

/// The location of the 'class' keyword for class-bound protocols.
SourceLoc ClassRequirementLoc;

/// The syntactic representation of the where clause in a protocol like
/// `protocol ... where ... { ... }`.
TrailingWhereClause *TrailingWhere;
Expand Down Expand Up @@ -3571,17 +3568,6 @@ class ProtocolDecl : public NominalTypeDecl {
ProtocolDeclBits.RequiresClass = requiresClass;
}

/// Specify that this protocol is class-bounded, recording the location of
/// the 'class' keyword.
void setClassBounded(SourceLoc loc) {
ClassRequirementLoc = loc;
ProtocolDeclBits.RequiresClassValid = true;
ProtocolDeclBits.RequiresClass = true;
}

/// Retrieve the source location of the 'class' keyword.
SourceLoc getClassBoundedLoc() const { return ClassRequirementLoc; }

/// Determine whether an existential conforming to this protocol can be
/// matched with a generic type parameter constrained to this protocol.
/// This is only permitted if there is nothing "non-trivial" that we
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,7 @@ class Parser {
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
DeclAttributes &Attributes);
ParserStatus parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
SourceLoc *classRequirementLoc);
bool allowClassRequirement);
ParserStatus parseDeclItem(bool &PreviousHadSemi,
Parser::ParseDeclOptions Options,
llvm::function_ref<void(Decl*)> handler);
Expand Down
50 changes: 14 additions & 36 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -989,11 +989,9 @@ class PrintAST : public ASTVisitor<PrintAST> {
void printInherited(const Decl *decl,
ArrayRef<TypeLoc> inherited,
ArrayRef<ProtocolDecl *> protos,
Type superclass = {},
bool explicitClass = false);
Type superclass = {});

void printInherited(const NominalTypeDecl *decl,
bool explicitClass = false);
void printInherited(const NominalTypeDecl *decl);
void printInherited(const EnumDecl *D);
void printInherited(const ExtensionDecl *decl);
void printInherited(const GenericTypeParamDecl *D);
Expand Down Expand Up @@ -1312,8 +1310,12 @@ bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req) {

// A requirement like Self : Protocol or Self.T : Class might be from an
// inheritance, or might be a where clause.
if (req.getKind() != RequirementKind::Layout && result.second) {
auto inherited = req.getSecondType();
if (result.second) {
Type inherited;
if (req.getKind() == RequirementKind::Layout)
inherited = proto->getASTContext().getAnyObjectType();
else
inherited = req.getSecondType();
inWhereClause =
none_of(result.first->getInherited(), [&](const TypeLoc &loc) {
return loc.getType()->isEqual(inherited);
Expand Down Expand Up @@ -2049,9 +2051,8 @@ void PrintAST::printNominalDeclGenericRequirements(NominalTypeDecl *decl) {
void PrintAST::printInherited(const Decl *decl,
ArrayRef<TypeLoc> inherited,
ArrayRef<ProtocolDecl *> protos,
Type superclass,
bool explicitClass) {
if (inherited.empty() && superclass.isNull() && !explicitClass) {
Type superclass) {
if (inherited.empty() && superclass.isNull()) {
if (protos.empty())
return;
}
Expand All @@ -2060,10 +2061,7 @@ void PrintAST::printInherited(const Decl *decl,
bool PrintedColon = false;
bool PrintedInherited = false;

if (explicitClass) {
Printer << " : " << tok::kw_class;
PrintedInherited = true;
} else if (superclass) {
if (superclass) {
bool ShouldPrintSuper = true;
if (auto NTD = superclass->getAnyNominal()) {
ShouldPrintSuper = shouldPrint(NTD);
Expand Down Expand Up @@ -2115,9 +2113,6 @@ void PrintAST::printInherited(const Decl *decl,

Printer << " : ";

if (explicitClass)
Printer << " " << tok::kw_class << ", ";

interleave(TypesToPrint, [&](TypeLoc TL) {
printTypeLoc(TL);
}, [&]() {
Expand All @@ -2126,9 +2121,8 @@ void PrintAST::printInherited(const Decl *decl,
}
}

void PrintAST::printInherited(const NominalTypeDecl *decl,
bool explicitClass) {
printInherited(decl, decl->getInherited(), { }, nullptr, explicitClass);
void PrintAST::printInherited(const NominalTypeDecl *decl) {
printInherited(decl, decl->getInherited(), { }, nullptr);
}

void PrintAST::printInherited(const EnumDecl *decl) {
Expand Down Expand Up @@ -2539,23 +2533,7 @@ void PrintAST::visitProtocolDecl(ProtocolDecl *decl) {
Printer.printName(decl->getName());
});

// Figure out whether we need an explicit 'class' in the inheritance.
bool explicitClass = false;
if (decl->requiresClass() && !decl->isObjC()) {
bool inheritsRequiresClass = false;
for (auto proto : decl->getLocalProtocols(
ConformanceLookupKind::OnlyExplicit)) {
if (proto->requiresClass()) {
inheritsRequiresClass = true;
break;
}
}

if (!inheritsRequiresClass)
explicitClass = true;
}

printInherited(decl, explicitClass);
printInherited(decl);

// The trailing where clause is a syntactic thing, which isn't serialized
// (etc.) and thus isn't available for printing things out of
Expand Down
37 changes: 18 additions & 19 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2630,13 +2630,11 @@ ParserResult<ImportDecl> Parser::parseDeclImport(ParseDeclOptions Flags,
/// type-identifier
/// \endverbatim
ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
SourceLoc *classRequirementLoc) {
bool allowClassRequirement) {
Scope S(this, ScopeKind::InheritanceClause);
consumeToken(tok::colon);

// Clear out the class requirement location.
if (classRequirementLoc)
*classRequirementLoc = SourceLoc();
SourceLoc classRequirementLoc;

ParserStatus Status;
SourceLoc prevComma;
Expand All @@ -2645,17 +2643,17 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
if (Tok.is(tok::kw_class)) {
// If we aren't allowed to have a class requirement here, complain.
auto classLoc = consumeToken();
if (!classRequirementLoc) {
if (!allowClassRequirement) {
SourceLoc endLoc = Tok.is(tok::comma) ? Tok.getLoc() : classLoc;
diagnose(classLoc, diag::invalid_class_requirement)
.fixItRemove(SourceRange(classLoc, endLoc));
continue;
}

// If we already saw a class requirement, complain.
if (classRequirementLoc->isValid()) {
if (classRequirementLoc.isValid()) {
diagnose(classLoc, diag::redundant_class_requirement)
.highlight(*classRequirementLoc)
.highlight(classRequirementLoc)
.fixItRemove(SourceRange(prevComma, classLoc));
continue;
}
Expand All @@ -2669,7 +2667,12 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
}

// Record the location of the 'class' keyword.
*classRequirementLoc = classLoc;
classRequirementLoc = classLoc;

// Add 'AnyObject' to the inherited list.
Inherited.push_back(
new (Context) SimpleIdentTypeRepr(classLoc,
Context.getIdentifier("AnyObject")));
continue;
}

Expand Down Expand Up @@ -2933,7 +2936,7 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
// Parse optional inheritance clause.
SmallVector<TypeLoc, 2> Inherited;
if (Tok.is(tok::colon))
status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);

// Parse the optional where-clause.
TrailingWhereClause *trailingWhereClause = nullptr;
Expand Down Expand Up @@ -3270,7 +3273,7 @@ ParserResult<TypeDecl> Parser::parseDeclAssociatedType(Parser::ParseDeclOptions
// FIXME: Allow class requirements here.
SmallVector<TypeLoc, 2> Inherited;
if (Tok.is(tok::colon))
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);

ParserResult<TypeRepr> UnderlyingTy;
if (Tok.is(tok::equal)) {
Expand Down Expand Up @@ -5000,7 +5003,7 @@ ParserResult<EnumDecl> Parser::parseDeclEnum(ParseDeclOptions Flags,
if (Tok.is(tok::colon)) {
ContextChange CC(*this, ED);
SmallVector<TypeLoc, 2> Inherited;
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);
ED->setInherited(Context.AllocateCopy(Inherited));
}

Expand Down Expand Up @@ -5263,7 +5266,7 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
if (Tok.is(tok::colon)) {
ContextChange CC(*this, SD);
SmallVector<TypeLoc, 2> Inherited;
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);
SD->setInherited(Context.AllocateCopy(Inherited));
}

Expand Down Expand Up @@ -5351,7 +5354,7 @@ ParserResult<ClassDecl> Parser::parseDeclClass(SourceLoc ClassLoc,
if (Tok.is(tok::colon)) {
ContextChange CC(*this, CD);
SmallVector<TypeLoc, 2> Inherited;
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);
CD->setInherited(Context.AllocateCopy(Inherited));
}

Expand Down Expand Up @@ -5439,11 +5442,11 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {

// Parse optional inheritance clause.
SmallVector<TypeLoc, 4> InheritedProtocols;
SourceLoc classRequirementLoc;
SourceLoc colonLoc;
if (Tok.is(tok::colon)) {
colonLoc = Tok.getLoc();
Status |= parseInheritance(InheritedProtocols, &classRequirementLoc);
Status |= parseInheritance(InheritedProtocols,
/*allowClassRequirement=*/true);
}

TrailingWhereClause *TrailingWhere = nullptr;
Expand All @@ -5460,10 +5463,6 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
Context.AllocateCopy(InheritedProtocols), TrailingWhere);
// No need to setLocalDiscriminator: protocols can't appear in local contexts.

// If there was a 'class' requirement, mark this as a class-bounded protocol.
if (classRequirementLoc.isValid())
Proto->setClassBounded(classRequirementLoc);

Proto->getAttrs() = Attributes;

ContextChange CC(*this, Proto);
Expand Down
2 changes: 1 addition & 1 deletion test/IDE/print_ast_tc_decls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ protocol d0130_TestProtocol {
}

protocol d0150_TestClassProtocol : class {}
// PASS_COMMON-LABEL: {{^}}protocol d0150_TestClassProtocol : class {{{$}}
// PASS_COMMON-LABEL: {{^}}protocol d0150_TestClassProtocol : AnyObject {{{$}}

@objc protocol d0151_TestClassProtocol {}
// PASS_COMMON-LABEL: {{^}}@objc protocol d0151_TestClassProtocol {{{$}}
Expand Down
3 changes: 3 additions & 0 deletions test/IRGen/existentials_objc.sil
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@

sil_stage canonical

import Builtin
import gizmo

typealias AnyObject = Builtin.AnyObject

// rdar://16621578

sil @init_opaque_existential : $@convention(thin) <T where T : Gizmo> (@owned T) -> @out Any {
Expand Down
4 changes: 4 additions & 0 deletions test/IRGen/fixlifetime.sil
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@
// CHECK-native: call void @__swift_fixLifetime(%swift.refcounted*
// CHECK-native: call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%T11fixlifetime1CC**)*)(%T11fixlifetime1CC**

import Builtin

sil_stage canonical

typealias AnyObject = Builtin.AnyObject

class C {}
sil_vtable C {}
protocol P : class {}
Expand Down
4 changes: 4 additions & 0 deletions test/IRGen/unowned.sil
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
// CHECK: [[A:%T7unowned1AV]] = type <{ %swift.unowned }>

import Builtin

class C {}
sil_vtable C {}

typealias AnyObject = Builtin.AnyObject
protocol P : class {
func explode()
}
Expand Down
3 changes: 3 additions & 0 deletions test/IRGen/unowned_objc.sil
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// REQUIRES: CPU=x86_64
// XFAIL: linux

import Builtin

// These types end up in a completely different order with interop disabled.
// CHECK: [[TYPE:%swift.type]] = type
// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
Expand All @@ -12,6 +14,7 @@

class C {}
sil_vtable C {}
typealias AnyObject = Builtin.AnyObject
protocol P : class {
func explode()
}
Expand Down
2 changes: 2 additions & 0 deletions test/SIL/clone_init_existential.sil
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ sil_stage canonical

import Builtin

typealias AnyObject = Builtin.AnyObject

protocol ClassProto1 : class {
}

Expand Down
2 changes: 1 addition & 1 deletion test/SIL/ownership-verifier/use_verifier.sil
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Builtin

sil @allocate_object : $@convention(thin) () -> @owned Builtin.NativeObject

public protocol AnyObject : class {}
typealias AnyObject = Builtin.AnyObject

public protocol Error {}

Expand Down
2 changes: 2 additions & 0 deletions test/SILGen/class_bound_protocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ enum Optional<T> {

precedencegroup AssignmentPrecedence {}

typealias AnyObject = Builtin.AnyObject

// -- Class-bound archetypes and existentials are *not* address-only and can
// be manipulated using normal reference type value semantics.

Expand Down
4 changes: 2 additions & 2 deletions test/SILGen/objc_imported_generic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ public func genericBlockBridging<T: Ansible>(x: GenericClass<T>) {
}

// CHECK-LABEL: sil @_T021objc_imported_generic0C13BlockBridging{{[_0-9a-zA-Z]*}}F
// CHECK: [[BLOCK_TO_FUNC:%.*]] = function_ref @_T0xxIyBya_xxIxxo_RlzC21objc_imported_generic7AnsibleRzlTR
// CHECK: [[BLOCK_TO_FUNC:%.*]] = function_ref @_T0xxIyBya_xxIxxo_21objc_imported_generic7AnsibleRzlTR
// CHECK: partial_apply [[BLOCK_TO_FUNC]]<T>
// CHECK: [[FUNC_TO_BLOCK:%.*]] = function_ref @_T0xxIxxo_xxIyBya_RlzC21objc_imported_generic7AnsibleRzlTR
// CHECK: [[FUNC_TO_BLOCK:%.*]] = function_ref @_T0xxIxxo_xxIyBya_21objc_imported_generic7AnsibleRzlTR
// CHECK: init_block_storage_header {{.*}} invoke [[FUNC_TO_BLOCK]]<T>

// CHECK-LABEL: sil @_T021objc_imported_generic20arraysOfGenericParam{{[_0-9a-zA-Z]*}}F
Expand Down
1 change: 1 addition & 0 deletions test/SILOptimizer/address_projection.sil
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Builtin
sil_stage canonical
// CHECK: sil_stage lowered

typealias AnyObject = Builtin.AnyObject
typealias Int = Builtin.Int64

// CHECK-LABEL: sil hidden @f010_addrlower_identity : $@convention(thin) <T> (@in T) -> @out T {
Expand Down
2 changes: 2 additions & 0 deletions test/SILOptimizer/rcidentity.sil
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Builtin
// NonTest Utilities //
///////////////////////

typealias AnyObject = Builtin.AnyObject

protocol FakeAnyObject : class {}

class C : FakeAnyObject {
Expand Down
2 changes: 1 addition & 1 deletion test/SourceKit/CursorInfo/cursor_info.swift
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ func hasLocalizationKey2() {}
// FIXME: ref.class - rdar://problem/25014968

// RUN: %sourcekitd-test -req=cursor -pos=150:10 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | %FileCheck %s -check-prefix=CHECK66
// CHECK66: <decl.protocol><syntaxtype.keyword>protocol</syntaxtype.keyword> <decl.name>P2</decl.name> : <syntaxtype.keyword>class</syntaxtype.keyword>, <ref.protocol usr="s:11cursor_info2P1P">P1</ref.protocol></decl.protocol>
// CHECK66: <decl.protocol><syntaxtype.keyword>protocol</syntaxtype.keyword> <decl.name>P2</decl.name> : <ref.typealias usr="s:s9AnyObjecta">AnyObject</ref.typealias>, <ref.protocol usr="s:11cursor_info2P1P">P1</ref.protocol></decl.protocol>

// RUN: %sourcekitd-test -req=cursor -pos=114:18 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | %FileCheck %s -check-prefix=CHECK67
// CHECK67: source.lang.swift.decl.associatedtype (114:18-114:19)
Expand Down
2 changes: 2 additions & 0 deletions test/decl/protocol/req/class.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ protocol P1 : class { }
protocol P2 : class, class { } // expected-error{{redundant 'class' requirement}}{{20-27=}}

protocol P3 : P2, class { } // expected-error{{'class' must come first in the requirement list}}{{15-15=class, }}{{17-24=}}
// expected-warning@-1 {{redundant layout constraint 'Self' : 'AnyObject'}}
// expected-note@-2 {{layout constraint constraint 'Self' : 'AnyObject' implied here}}

struct X : class { } // expected-error{{'class' requirement only applies to protocols}} {{12-18=}}