Skip to content

Sema: Always allow method overrides to be as available as the context #78937

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
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
6 changes: 6 additions & 0 deletions lib/Sema/TypeCheckAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1575,6 +1575,12 @@ TypeChecker::availabilityAtLocation(SourceLoc loc, const DeclContext *DC,
return availability;
}

AvailabilityContext
TypeChecker::availabilityForDeclSignature(const Decl *decl) {
return TypeChecker::availabilityAtLocation(decl->getLoc(),
decl->getInnermostDeclContext());
}

AvailabilityRange TypeChecker::overApproximateAvailabilityAtLocation(
SourceLoc loc, const DeclContext *DC,
const AvailabilityScope **MostRefined) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeCheckDeclOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1817,10 +1817,10 @@ static bool isAvailabilitySafeForOverride(ValueDecl *override,

// Allow overrides that are not as available as the base decl as long as the
// override is as available as its context.
auto overrideTypeAvailability = AvailabilityInference::availableRange(
auto availabilityContext = TypeChecker::availabilityForDeclSignature(
override->getDeclContext()->getSelfNominalTypeDecl());

return overrideTypeAvailability.isContainedIn(overrideInfo);
return availabilityContext.getPlatformRange().isContainedIn(overrideInfo);
}

/// Returns true if a diagnostic about an accessor being less available
Expand Down
3 changes: 3 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,9 @@ AvailabilityContext
availabilityAtLocation(SourceLoc loc, const DeclContext *DC,
const AvailabilityScope **MostRefined = nullptr);

/// Returns the availability context of the signature of the given declaration.
AvailabilityContext availabilityForDeclSignature(const Decl *decl);

/// Returns an over-approximation of the range of operating system versions
/// that could the passed-in location could be executing upon for
/// the target platform. If MostRefined != nullptr, set to the most-refined
Expand Down
63 changes: 57 additions & 6 deletions test/Sema/availability_versions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ protocol BaseProto {

var property: A { get set } // expected-note {{overridden declaration is here}}

@available(OSX 10.51, *)
@available(OSX 51, *)
var newProperty: A { get set } // expected-note {{overridden declaration is here}}

func method() // expected-note {{overridden declaration is here}}
Expand All @@ -247,24 +247,24 @@ protocol BaseProto {
protocol RefinesBaseProto_AsAvailableOverrides: BaseProto {
var property: A { get set }

@available(OSX 10.51, *)
@available(OSX 51, *)
var newProperty: A { get set }

func method()
}

protocol RefinesBaseProto_LessAvailableOverrides: BaseProto {
@available(OSX 10.52, *)
@available(OSX 52, *)
var property: A { get set } // expected-error {{overriding 'property' must be as available as declaration it overrides}}

@available(OSX 10.52, *)
@available(OSX 52, *)
var newProperty: A { get set } // expected-error {{overriding 'newProperty' must be as available as declaration it overrides}}

@available(OSX 10.52, *)
@available(OSX 52, *)
func method() // expected-error {{overriding 'method' must be as available as declaration it overrides}}
}

@available(OSX 10.52, *)
@available(OSX 52, *)
protocol RefinesBaseProto_LessAvailable: BaseProto {
var property: A { get set }
var newProperty: A { get set }
Expand Down Expand Up @@ -892,6 +892,57 @@ class SubWithLimitedMemberAvailability : SuperWithAlwaysAvailableMembers {
}
}

extension ClassAvailableOn10_9 {
class NestedSubWithLimitedMemberAvailability: SuperWithAlwaysAvailableMembers {
@available(OSX, introduced: 10.9)
override func shouldAlwaysBeAvailableMethod() {}

@available(OSX, introduced: 10.9)
override var shouldAlwaysBeAvailableProperty: Int {
get { return 10 }
set(newVal) {}
}

override var setterShouldAlwaysBeAvailableProperty: Int {
get { return 9 }
@available(OSX, introduced: 10.9)
set(newVal) {}
}

override var getterShouldAlwaysBeAvailableProperty: Int {
@available(OSX, introduced: 10.9)
get { return 9 }
set(newVal) {}
}
}
}

@available(OSX, introduced: 51)
extension ClassAvailableOn51 {
class NestedSubWithLimitedMemberAvailability: SuperWithAlwaysAvailableMembers {
@available(OSX, introduced: 51)
override func shouldAlwaysBeAvailableMethod() {}

@available(OSX, introduced: 51)
override var shouldAlwaysBeAvailableProperty: Int {
get { return 10 }
set(newVal) {}
}

override var setterShouldAlwaysBeAvailableProperty: Int {
get { return 9 }
@available(OSX, introduced: 51)
set(newVal) {}
}

override var getterShouldAlwaysBeAvailableProperty: Int {
@available(OSX, introduced: 51)
get { return 9 }
set(newVal) {}
}
}
}

@available(OSX, introduced: 51)
class SubWithLimitedAvailablility : SuperWithAlwaysAvailableMembers {
override func shouldAlwaysBeAvailableMethod() {}
Expand Down
167 changes: 167 additions & 0 deletions test/attr/attr_inlinable_available.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1690,3 +1690,170 @@ public enum UnavailableEnumWithClasses {
public class InheritsAfterDeploymentTarget: AfterDeploymentTargetClass {}
public class InheritsUnavailable: UnavailableClass {}
}

// MARK: - Overrides

public class Base {
@available(macOS 10.9, *)
public func beforeInliningTargetMethod() {} // expected-note 3 {{overridden declaration is here}}

@available(macOS 10.10, *)
public func atInliningTargetMethod() {}// expected-note 3 {{overridden declaration is here}}

@available(macOS 10.14.5, *)
public func betweenTargetsMethod() {}// expected-note 3 {{overridden declaration is here}}

@available(macOS 10.15, *)
public func atDeploymentTargetMethod() {}// expected-note 2 {{overridden declaration is here}}

@available(macOS 11, *)
public func afterDeploymentTargetMethod() {}// expected-note {{overridden declaration is here}}
}

public class DerivedNoAvailable: Base {
public override func beforeInliningTargetMethod() {}
public override func atInliningTargetMethod() {}
public override func betweenTargetsMethod() {}
public override func atDeploymentTargetMethod() {}
public override func afterDeploymentTargetMethod() {}
}

@available(macOS 10.9, *)
public class DerivedBeforeInliningTarget: Base {
@available(macOS 10.9, *)
public override func beforeInliningTargetMethod() {}
@available(macOS 10.9, *)
public override func atInliningTargetMethod() {}
@available(macOS 10.9, *)
public override func betweenTargetsMethod() {}
@available(macOS 10.9, *)
public override func atDeploymentTargetMethod() {}
@available(macOS 10.9, *)
public override func afterDeploymentTargetMethod() {}
}

@available(macOS 10.10, *)
public class DerivedAtInliningTarget: Base {
@available(macOS 10.10, *)
public override func beforeInliningTargetMethod() {}
@available(macOS 10.10, *)
public override func atInliningTargetMethod() {}
@available(macOS 10.10, *)
public override func betweenTargetsMethod() {}
@available(macOS 10.10, *)
public override func atDeploymentTargetMethod() {}
@available(macOS 10.10, *)
public override func afterDeploymentTargetMethod() {}
}

@available(macOS 10.14.5, *)
public class DerivedBetweenTargets: Base {
@available(macOS 10.14.5, *)
public override func beforeInliningTargetMethod() {}
@available(macOS 10.14.5, *)
public override func atInliningTargetMethod() {}
@available(macOS 10.14.5, *)
public override func betweenTargetsMethod() {}
@available(macOS 10.14.5, *)
public override func atDeploymentTargetMethod() {}
@available(macOS 10.14.5, *)
public override func afterDeploymentTargetMethod() {}
}

@available(macOS 10.15, *)
public class DerivedAtDeploymentTarget: Base {
@available(macOS 10.15, *)
public override func beforeInliningTargetMethod() {}
@available(macOS 10.15, *)
public override func atInliningTargetMethod() {}
@available(macOS 10.15, *)
public override func betweenTargetsMethod() {}
@available(macOS 10.15, *)
public override func atDeploymentTargetMethod() {}
@available(macOS 10.15, *)
public override func afterDeploymentTargetMethod() {}
}

@available(macOS 11, *)
public class DerivedAfterDeploymentTarget: Base {
@available(macOS 11, *)
public override func beforeInliningTargetMethod() {}
@available(macOS 11, *)
public override func atInliningTargetMethod() {}
@available(macOS 11, *)
public override func betweenTargetsMethod() {}
@available(macOS 11, *)
public override func atDeploymentTargetMethod() {}
@available(macOS 11, *)
public override func afterDeploymentTargetMethod() {}
}

public class DerivedAtDeploymentTargetOverrides: Base {
@available(macOS 10.15, *)
public override func beforeInliningTargetMethod() {} // expected-error {{overriding 'beforeInliningTargetMethod' must be as available as declaration it overrides}}

@available(macOS 10.15, *)
public override func atInliningTargetMethod() {} // expected-error {{overriding 'atInliningTargetMethod' must be as available as declaration it overrides}}

@available(macOS 10.15, *)
public override func betweenTargetsMethod() {} // expected-error {{overriding 'betweenTargetsMethod' must be as available as declaration it overrides}}

@available(macOS 10.15, *)
public override func atDeploymentTargetMethod() {}

@available(macOS 10.15, *)
public override func afterDeploymentTargetMethod() {}
}

public class DerivedFutureOverrides: Base {
@available(macOS 12, *)
public override func beforeInliningTargetMethod() {} // expected-error {{overriding 'beforeInliningTargetMethod' must be as available as declaration it overrides}}

@available(macOS 12, *)
public override func atInliningTargetMethod() {} // expected-error {{overriding 'atInliningTargetMethod' must be as available as declaration it overrides}}

@available(macOS 12, *)
public override func betweenTargetsMethod() {} // expected-error {{overriding 'betweenTargetsMethod' must be as available as declaration it overrides}}

@available(macOS 12, *)
public override func atDeploymentTargetMethod() {} // expected-error {{overriding 'atDeploymentTargetMethod' must be as available as declaration it overrides}}

@available(macOS 12, *)
public override func afterDeploymentTargetMethod() {} // expected-error {{overriding 'afterDeploymentTargetMethod' must be as available as declaration it overrides}}
}

extension AtDeploymentTarget {
public class DerivedAtDeploymentTargetOverrides: Base {
@available(macOS 10.15, *)
public override func beforeInliningTargetMethod() {}

@available(macOS 10.15, *)
public override func atInliningTargetMethod() {}

@available(macOS 10.15, *)
public override func betweenTargetsMethod() {}

@available(macOS 10.15, *)
public override func atDeploymentTargetMethod() {}

@available(macOS 10.15, *)
public override func afterDeploymentTargetMethod() {}
}

public class DerivedAfterDeploymentTargetOverrides: Base {
@available(macOS 11, *)
public override func beforeInliningTargetMethod() {} // expected-error {{overriding 'beforeInliningTargetMethod' must be as available as declaration it overrides}}

@available(macOS 11, *)
public override func atInliningTargetMethod() {} // expected-error {{overriding 'atInliningTargetMethod' must be as available as declaration it overrides}}

@available(macOS 11, *)
public override func betweenTargetsMethod() {} // expected-error {{overriding 'betweenTargetsMethod' must be as available as declaration it overrides}}

@available(macOS 11, *)
public override func atDeploymentTargetMethod() {} // expected-error {{overriding 'atDeploymentTargetMethod' must be as available as declaration it overrides}}

@available(macOS 11, *)
public override func afterDeploymentTargetMethod() {}
}
}