Skip to content

Ncgenerics test fixes kavon v4 #71438

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 4 commits into from
Feb 8, 2024
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
4 changes: 2 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2537,8 +2537,8 @@ ERROR(invalid_nominal_extension,none,
(Type, Type))
NOTE(invalid_extension_rewrite,none,
"did you mean to extend %0 instead?", (Type))
ERROR(synthesized_nominal_extension,none,
"cannot extend synthesized type %0", (Type))
ERROR(cannot_extend_nominal,none,
"cannot extend %kind0", (const NominalTypeDecl *))

ERROR(retroactive_not_in_extension_inheritance_clause,none,
"'retroactive' attribute only applies in inheritance clauses in "
Expand Down
22 changes: 11 additions & 11 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,20 +1076,10 @@ void NominalTypeDecl::prepareConformanceTable() const {
}

SmallPtrSet<ProtocolDecl *, 2> protocols;
const bool haveNoncopyableGenerics =
ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics);

auto addSynthesized = [&](ProtocolDecl *proto) {
if (!proto)
return;

// No synthesized conformances for move-only nominals.
if (!haveNoncopyableGenerics && !canBeCopyable()) {
// assumption is Sendable gets synthesized elsewhere.
assert(!proto->isSpecificProtocol(KnownProtocolKind::Sendable));
return;
}

if (protocols.count(proto) == 0) {
ConformanceTable->addSynthesizedConformance(
mutableThis, proto, mutableThis);
Expand All @@ -1099,12 +1089,22 @@ void NominalTypeDecl::prepareConformanceTable() const {

// Synthesize the unconditional conformances to invertible protocols.
// For conditional ones, see findSynthesizedConformances .
if (haveNoncopyableGenerics) {
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
bool missingOne = false;
for (auto ip : InvertibleProtocolSet::full()) {
auto invertible = getMarking(ip);
if (!invertible.getInverse() || bool(invertible.getPositive()))
addSynthesized(ctx.getProtocol(getKnownProtocolKind(ip)));
else
missingOne = true;
}

// FIXME: rdar://122289155 (NCGenerics: convert Equatable, Hashable, and RawRepresentable to ~Copyable.)
if (missingOne)
return;

} else if (!canBeCopyable()) {
return; // No synthesized conformances for move-only nominals.
}

// Add protocols for any synthesized protocol attributes.
Expand Down
10 changes: 3 additions & 7 deletions lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,15 +625,11 @@ bool BindingSet::finalize(
for (auto *constraint : *TransitiveProtocols) {
Type protocolTy = constraint->getSecondType();

// The Copyable/Escapable protocols can't have members, yet will be a
// constraint of basically all type variables, so don't suggest it.
//
// NOTE: worth considering for all marker protocols, but keep in
// mind that you're allowed to extend them with members!
// Compiler-known marker protocols cannot be extended with members,
// so do not consider them.
if (auto p = protocolTy->getAs<ProtocolType>()) {
if (ProtocolDecl *decl = p->getDecl())
if (decl->isSpecificProtocol(KnownProtocolKind::Copyable) ||
decl->isSpecificProtocol(KnownProtocolKind::Escapable))
if (decl->getKnownProtocolKind() && decl->isMarkerProtocol())
continue;
}

Expand Down
7 changes: 4 additions & 3 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11908,9 +11908,10 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1,
if (type1->isTypeVariableOrMember() || type2->isTypeVariableOrMember())
return formUnsolved();

// Noncopyable types can't be involved in bridging conversions since a bridged
// type assumes the ability to copy.
if (type1->isNoncopyable()) {
// Noncopyable & Nonescapable types can't be involved in bridging conversions
// since a bridged type assumes such abilities are granted.
if (!type1->hasTypeVariable()
&& (type1->isNoncopyable() || !type1->isEscapable())) {
return SolutionKind::Error;
}

Expand Down
48 changes: 26 additions & 22 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1957,29 +1957,33 @@ TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,

// A cast from a function type to an existential type (except `Any`)
// or an archetype type (with constraints) cannot succeed
auto toArchetypeType = toType->is<ArchetypeType>();
auto fromFunctionType = fromType->is<FunctionType>();
auto toExistentialType = toType->isAnyExistentialType();

auto toConstrainedArchetype = false;
if (toArchetypeType) {
auto archetype = toType->castTo<ArchetypeType>();
toConstrainedArchetype = !archetype->getConformsTo().empty();
}

if (fromFunctionType &&
(toExistentialType || (toArchetypeType && toConstrainedArchetype))) {
switch (contextKind) {
case CheckedCastContextKind::None:
case CheckedCastContextKind::ConditionalCast:
case CheckedCastContextKind::ForcedCast:
return CheckedCastKind::Unresolved;
if (fromType->is<FunctionType>()) {
auto toArchetypeType = toType->is<ArchetypeType>();
auto toExistentialType = toType->isAnyExistentialType();

auto conformsToAllProtocols = true;
if (toArchetypeType) {
auto archetype = toType->castTo<ArchetypeType>();
conformsToAllProtocols = llvm::all_of(archetype->getConformsTo(),
[&](ProtocolDecl *proto) {
return module->checkConformance(fromType, proto,
/*allowMissing=*/false);
});
}

case CheckedCastContextKind::IsPattern:
case CheckedCastContextKind::EnumElementPattern:
case CheckedCastContextKind::IsExpr:
case CheckedCastContextKind::Coercion:
break;
if (toExistentialType || (toArchetypeType && !conformsToAllProtocols)) {
switch (contextKind) {
case CheckedCastContextKind::None:
case CheckedCastContextKind::ConditionalCast:
case CheckedCastContextKind::ForcedCast:
return CheckedCastKind::Unresolved;

case CheckedCastContextKind::IsPattern:
case CheckedCastContextKind::EnumElementPattern:
case CheckedCastContextKind::IsExpr:
case CheckedCastContextKind::Coercion:
break;
}
}
}

Expand Down
11 changes: 11 additions & 0 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3676,6 +3676,16 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
return true;
}

/// Compiler-known marker protocols cannot be extended with members.
static void diagnoseExtensionOfMarkerProtocol(ExtensionDecl *ED) {
auto *nominal = ED->getExtendedNominal();
if (auto *proto = dyn_cast_or_null<ProtocolDecl>(nominal)) {
if (proto->getKnownProtocolKind() && proto->isMarkerProtocol()) {
ED->diagnose(diag::cannot_extend_nominal, nominal);
}
}
}

static void checkTupleExtension(ExtensionDecl *ED) {
auto *nominal = ED->getExtendedNominal();
if (!nominal || !isa<BuiltinTupleDecl>(nominal))
Expand Down Expand Up @@ -3878,6 +3888,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
TypeChecker::checkDistributedActor(SF, nominal);

diagnoseIncompatibleProtocolsForMoveOnlyType(ED);
diagnoseExtensionOfMarkerProtocol(ED);

checkTupleExtension(ED);
}
Expand Down
6 changes: 2 additions & 4 deletions test/Concurrency/sendable_objc_protocol_attr.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ struct MyStruct: Sendable {
let value: any MyObjCProtocol // Ok
}

extension Sendable {
func compute() {}
}
func compute<T: Sendable>(_ t: T) {}

extension MyObjCProtocol {
func test() {
compute() // Ok
compute(self) // Ok
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,21 +350,16 @@ func test_leading_dot_syntax_with_typelias() {
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
}

extension Copyable where Self == Int {
static func answer() -> Int { 42 }
}
// User-defined marker protocols do gain the inference for members, since they
// support extensions.
@_marker protocol SomeMarkerProto {}
extension Int: SomeMarkerProto {}

extension Escapable where Self == String {
static func question() -> String { "" }
extension SomeMarkerProto where Self == Int {
static func answer() -> Int { 42 }
}

do {
func testCopyable<T: Copyable>(_: T) {}
func testEscapable<T: Escapable>(_: T) {}

testCopyable(.answer())
// expected-error@-1 {{cannot infer contextual base in reference to member 'answer'}}

testEscapable(.question())
// expected-error@-1 {{cannot infer contextual base in reference to member 'question'}}
func testSomeMarkerProto<T: SomeMarkerProto>(_: T) {}
testSomeMarkerProto(.answer())
}
10 changes: 10 additions & 0 deletions test/Interpreter/casts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,13 @@ Casts.test("testCastProtocolWithAnyObjectToProtocolCompoTypeSuperclass") {
let shouldBeNil = (F() as QAny) as? KQAny
expectNil(shouldBeNil)
}

func f1() -> Any { return 1 }
func attemptFunctionCast<U>(_ u: U.Type) -> U? {
return f1 as? U
}
Casts.test("testFunctionCastToArchetype") {
expectNil(attemptFunctionCast(Int.self))
expectNil(attemptFunctionCast(K.self))
expectTrue(attemptFunctionCast(Any.self) != nil)
}
11 changes: 10 additions & 1 deletion test/Interpreter/protocol_extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import StdlibUnittest

defer { runAllTests() }

var ProtocolExtensionTestSuite = TestSuite("ProtocolExtensions")

Expand Down Expand Up @@ -363,4 +364,12 @@ ProtocolExtensionTestSuite.test("WitnessSelf") {
}
}

runAllTests()
@_marker protocol Addable {}
extension Addable {
func increment(this x: Int) -> Int { return x + 100 }
}
extension String: Addable {}

ProtocolExtensionTestSuite.test("MarkerProtocolExtensions") {
expectTrue("hello".increment(this: 11) == 111)
}
4 changes: 4 additions & 0 deletions test/Sema/copyable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ enum namespace {

func Copyable() -> Copyable { return 0 }
}

extension Copyable { // expected-error {{cannot extend protocol 'Copyable'}}
func hello() {}
}
13 changes: 0 additions & 13 deletions test/Sema/moveonly_sendable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,19 +150,6 @@ func createContainer(_ fd: borrowing FileDescriptor) {
let _: Container<Sendable> = Container(CopyableStruct())
}

func takeTwo<T: Sendable>(_ s1: T, _ s2: T) {}

extension Sendable {
func doIllegalThings() {
return takeTwo(self, self)
}
}

func tryToDupe(_ fd: borrowing FileDescriptor) {
// FIXME: this should describe 'Self' as 'any Sendable' or something.
fd.doIllegalThings() // expected-error {{noncopyable type 'FileDescriptor' cannot be substituted for copyable generic parameter 'Self' in 'Sendable'}}
}

@_moveOnly
struct PaperAirplaneFile {
var fd: FileDescriptor
Expand Down
9 changes: 9 additions & 0 deletions test/decl/ext/extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,12 @@ extension B4 {
// expected-error@-1 {{extension of existential type 'B4' (aka 'any P4') is not supported}}
// expected-note@-2 {{did you mean to extend 'P4' instead?}} {{11-13=P4}}
}


extension Sendable {} // expected-error {{cannot extend protocol 'Sendable'}}
extension Copyable {} // expected-error {{cannot extend protocol 'Copyable'}}
extension Escapable {} // expected-error {{cannot extend protocol 'Escapable'}}
extension _BitwiseCopyable {} // expected-error {{cannot extend protocol '_BitwiseCopyable'}}

@_marker protocol MyMarkerProto {}
extension MyMarkerProto {} // OK
21 changes: 17 additions & 4 deletions test/expr/cast/as_coerce.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ protocol P_48579 {}
do {
func f1() -> Any {}
func f2() {}
@Sendable func f3() {}

_ = f1 is P_48579 // expected-warning {{cast from '() -> Any' to unrelated type 'any P_48579' always fails}} // expected-note {{did you mean to call 'f1' with '()'?}}{{9-9=()}}
_ = f1 as! P_48579 // expected-warning {{cast from '() -> Any' to unrelated type 'any P_48579' always fails}} // expected-note {{did you mean to call 'f1' with '()'?}}{{9-9=()}}
Expand All @@ -133,20 +134,32 @@ do {
_ = f2 as? Any // expected-warning {{conditional cast from '() -> ()' to 'Any' always succeeds}}


func test1<T: P_48579>(_: T.Type) {
func test1<T: P_48579, V: P_48579 & Sendable>(_: T.Type, _: V.Type) {
_ = f1 is T // expected-warning {{cast from '() -> Any' to unrelated type 'T' always fails}} // expected-note {{did you mean to call 'f1' with '()'?}}{{11-11=()}}
_ = f1 as! T // expected-warning {{cast from '() -> Any' to unrelated type 'T' always fails}} // expected-note {{did you mean to call 'f1' with '()'?}}{{11-11=()}}
_ = f1 as! V // expected-warning {{cast from '() -> Any' to unrelated type 'V' always fails}} // expected-note {{did you mean to call 'f1' with '()'?}}{{11-11=()}}
_ = f1 as? T // expected-warning {{cast from '() -> Any' to unrelated type 'T' always fails}} // expected-note {{did you mean to call 'f1' with '()'?}}{{11-11=()}}
_ = f2 is T // expected-warning {{cast from '() -> ()' to unrelated type 'T' always fails}}
_ = f2 as! T // expected-warning {{cast from '() -> ()' to unrelated type 'T' always fails}}
_ = f2 as! V // expected-warning {{cast from '() -> ()' to unrelated type 'V' always fails}}
_ = f2 as? T // expected-warning {{cast from '() -> ()' to unrelated type 'T' always fails}}
_ = f3 is T // expected-warning {{cast from '@Sendable () -> ()' to unrelated type 'T' always fails}}
_ = f3 as! V // expected-warning {{cast from '@Sendable () -> ()' to unrelated type 'V' always fails}}
_ = f3 as? T // expected-warning {{cast from '@Sendable () -> ()' to unrelated type 'T' always fails}}
}

func test2<U>(_: U.Type) {
func test2<U, S: Sendable>(_: U.Type, _: S.Type) {
_ = f1 is U // Okay
_ = f1 as! U // Okay
_ = f1 as? U // Okay
_ = f1 is U // Okay
_ = f2 as! U // Okay
_ = f2 as? U // Okay

_ = f2 is S // expected-warning {{cast from '() -> ()' to unrelated type 'S' always fails}}
_ = f2 as! S // expected-warning {{cast from '() -> ()' to unrelated type 'S' always fails}}
_ = f2 as? S // expected-warning {{cast from '() -> ()' to unrelated type 'S' always fails}}
_ = f3 is S // Okay
_ = f3 as! S // Okay
_ = f3 as? S // Okay
}
}

Expand Down