Skip to content

Revert "Merge pull request #27057 from theblixguy/unrevert/SR-11298" #27611

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 1 commit into from
Oct 10, 2019
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
60 changes: 1 addition & 59 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,63 +58,6 @@ Swift 5.2
(foo as Magic)(5)
```

* [SR-11298][]:

A class-constrained protocol extension, where the extended protocol does
not impose a class constraint, will now infer the constraint implicitly.

```swift
protocol Foo {}
class Bar: Foo {
var someProperty: Int = 0
}

// Even though 'Foo' does not impose a class constraint, it is automatically
// inferred due to the Self: Bar constraint.
extension Foo where Self: Bar {
var anotherProperty: Int {
get { return someProperty }
// As a result, the setter is now implicitly nonmutating, just like it would
// be if 'Foo' had a class constraint.
set { someProperty = newValue }
}
}
```

As a result, this could lead to code that currently compiles today to throw an error.

```swift
protocol Foo {
var someProperty: Int { get set }
}

class Bar: Foo {
var someProperty = 0
}

extension Foo where Self: Bar {
var anotherProperty1: Int {
get { return someProperty }
// This will now error, because the protocol requirement
// is implicitly mutating and the setter is implicitly
// nonmutating.
set { someProperty = newValue } // Error
}
}
```

**Workaround**: Define a new mutable variable inside the setter that has a reference to `self`:

```swift
var anotherProperty1: Int {
get { return someProperty }
set {
var mutableSelf = self
mutableSelf.someProperty = newValue // Okay
}
}
```

* [SE-0253][]:

Values of types that declare `func callAsFunction` methods can be called
Expand All @@ -140,7 +83,7 @@ Swift 5.2

* [SR-4206][]:

A method override is no longer allowed to have a generic signature with
A method override is no longer allowed to have a generic signature with
requirements not imposed by the base method. For example:

```
Expand Down Expand Up @@ -7856,5 +7799,4 @@ Swift 1.0
[SR-8974]: <https://bugs.swift.org/browse/SR-8974>
[SR-9043]: <https://bugs.swift.org/browse/SR-9043>
[SR-9827]: <https://bugs.swift.org/browse/SR-9827>
[SR-11298]: <https://bugs.swift.org/browse/SR-11298>
[SR-11429]: <https://bugs.swift.org/browse/SR-11429>
5 changes: 1 addition & 4 deletions include/swift/AST/DeclContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,7 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {

/// Returns the kind of context this is.
DeclContextKind getContextKind() const;

/// Returns whether this context has value semantics.
bool hasValueSemantics() const;


/// Determines whether this context is itself a local scope in a
/// code block. A context that appears in such a scope, like a
/// local type declaration, does not itself become a local context.
Expand Down
10 changes: 2 additions & 8 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5672,18 +5672,12 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const {
if (FD && !FD->isMutating() && !FD->isImplicit() && FD->isInstanceMember()&&
!FD->getDeclContext()->getDeclaredInterfaceType()
->hasReferenceSemantics()) {
// Do not suggest the fix-it in implicit getters
// Do not suggest the fix it in implicit getters
if (auto AD = dyn_cast<AccessorDecl>(FD)) {
if (AD->isGetter() && !AD->getAccessorKeywordLoc().isValid())
return;

auto accessorDC = AD->getDeclContext();
// Do not suggest the fix-it if `Self` is a class type.
if (accessorDC->isTypeContext() && !accessorDC->hasValueSemantics()) {
return;
}
}

auto &d = getASTContext().Diags;
d.diagnose(FD->getFuncLoc(), diag::change_to_mutating,
isa<AccessorDecl>(FD))
Expand Down
8 changes: 0 additions & 8 deletions lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1035,14 +1035,6 @@ DeclContextKind DeclContext::getContextKind() const {
llvm_unreachable("Unhandled DeclContext ASTHierarchy");
}

bool DeclContext::hasValueSemantics() const {
if (auto contextTy = getSelfTypeInContext()) {
return !contextTy->hasReferenceSemantics();
}

return false;
}

SourceLoc swift::extractNearestSourceLoc(const DeclContext *dc) {
switch (dc->getContextKind()) {
case DeclContextKind::AbstractFunctionDecl:
Expand Down
12 changes: 10 additions & 2 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2090,10 +2090,17 @@ OperatorPrecedenceGroupRequest::evaluate(Evaluator &evaluator,
return group;
}

bool swift::doesContextHaveValueSemantics(DeclContext *dc) {
if (Type contextTy = dc->getDeclaredInterfaceType())
return !contextTy->hasReferenceSemantics();
return false;
}

llvm::Expected<SelfAccessKind>
SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
if (FD->getAttrs().getAttribute<MutatingAttr>(true)) {
if (!FD->isInstanceMember() || !FD->getDeclContext()->hasValueSemantics()) {
if (!FD->isInstanceMember() ||
!doesContextHaveValueSemantics(FD->getDeclContext())) {
return SelfAccessKind::NonMutating;
}
return SelfAccessKind::Mutating;
Expand All @@ -2115,7 +2122,8 @@ SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
case AccessorKind::MutableAddress:
case AccessorKind::Set:
case AccessorKind::Modify:
if (AD->isInstanceMember() && AD->getDeclContext()->hasValueSemantics())
if (AD->isInstanceMember() &&
doesContextHaveValueSemantics(AD->getDeclContext()))
return SelfAccessKind::Mutating;
break;

Expand Down
2 changes: 2 additions & 0 deletions lib/Sema/TypeCheckDecl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class DeclContext;
class ValueDecl;
class Pattern;

bool doesContextHaveValueSemantics(DeclContext *dc);

/// Walks up the override chain for \p CD until it finds an initializer that is
/// required and non-implicit. If no such initializer exists, returns the
/// declaration where \c required was introduced (i.e. closest to the root
Expand Down
12 changes: 5 additions & 7 deletions lib/Sema/TypeCheckStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,8 @@ void swift::validatePatternBindingEntries(TypeChecker &tc,
llvm::Expected<bool>
IsGetterMutatingRequest::evaluate(Evaluator &evaluator,
AbstractStorageDecl *storage) const {
auto storageDC = storage->getDeclContext();
bool result = (!storage->isStatic() && storageDC->isTypeContext() &&
storageDC->hasValueSemantics());
bool result = (!storage->isStatic() &&
doesContextHaveValueSemantics(storage->getDeclContext()));

// 'lazy' overrides the normal accessor-based rules and heavily
// restricts what accessors can be used. The getter is considered
Expand Down Expand Up @@ -299,7 +298,7 @@ IsGetterMutatingRequest::evaluate(Evaluator &evaluator,

// Protocol requirements are always written as '{ get }' or '{ get set }';
// the @_borrowed attribute determines if getReadImpl() becomes Get or Read.
if (isa<ProtocolDecl>(storageDC))
if (isa<ProtocolDecl>(storage->getDeclContext()))
return checkMutability(AccessorKind::Get);

switch (storage->getReadImpl()) {
Expand All @@ -325,9 +324,8 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator,
AbstractStorageDecl *storage) const {
// By default, the setter is mutating if we have an instance member of a
// value type, but this can be overridden below.
auto storageDC = storage->getDeclContext();
bool result = (!storage->isStatic() && storageDC->isTypeContext() &&
storageDC->hasValueSemantics());
bool result = (!storage->isStatic() &&
doesContextHaveValueSemantics(storage->getDeclContext()));

// If we have an attached property wrapper, the setter is mutating
// or not based on the composition of the wrappers.
Expand Down
8 changes: 4 additions & 4 deletions test/decl/ext/extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ struct WrapperContext {
}

// Class-constrained extension where protocol does not impose class requirement
// SR-11298

protocol DoesNotImposeClassReq_1 {}

class JustAClass: DoesNotImposeClassReq_1 {
Expand All @@ -140,8 +140,8 @@ extension DoesNotImposeClassReq_1 where Self: JustAClass {
}
}

let instanceOfJustAClass = JustAClass()
instanceOfJustAClass.wrappingProperty = "" // Okay
let instanceOfJustAClass = JustAClass() // expected-note {{change 'let' to 'var' to make it mutable}}
instanceOfJustAClass.wrappingProperty = "" // expected-error {{cannot assign to property: 'instanceOfJustAClass' is a 'let' constant}}

protocol DoesNotImposeClassReq_2 {
var property: String { get set }
Expand All @@ -150,7 +150,7 @@ protocol DoesNotImposeClassReq_2 {
extension DoesNotImposeClassReq_2 where Self : AnyObject {
var wrappingProperty: String {
get { property }
set { property = newValue } // expected-error {{cannot assign to property: 'self' is immutable}}
set { property = newValue } // Okay
}
}

Expand Down