mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Fixes rdar://problem/53407949 | SR-11138. Previously, we'd only look at the outermost property wrapper to decide whether the wrapped property's getter and setter were `mutating` (or exist at all). In reality, this requires considering the semantics of the composed accesses of each wrapper layer's `wrappedValue` property. Fixing this systematically addresses a number of issues: - As SR-11138 reported, composing a nonmutating-get-set wrapper ought to produce a composed wrapper that's nonmutating. - We would previously allow a property wrapper with a mutating getter to be nested inside one with only a getter, even though the resulting implementation was unsound (because there's no mutable context for the inner wrapper to execute its get on.) - Similarly, we would construct unsound setters in cases where the setter can't exist, such as when the nested wrapper isn't settable but the outer wrapper is.
181 lines
5.0 KiB
C++
181 lines
5.0 KiB
C++
//===--- AnyValue.h - Any Value Existential ---------------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the AnyValue class, which is used to store an
|
|
// immutable value of any type.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_BASIC_ANYVALUE_H
|
|
#define SWIFT_BASIC_ANYVALUE_H
|
|
|
|
#include "swift/Basic/SimpleDisplay.h"
|
|
#include "swift/Basic/TypeID.h"
|
|
#include "llvm/ADT/PointerUnion.h" // to define hash_value
|
|
#include "llvm/ADT/TinyPtrVector.h"
|
|
|
|
namespace llvm {
|
|
// FIXME: Belongs in LLVM itself
|
|
template<typename PT1, typename PT2>
|
|
hash_code hash_value(const llvm::PointerUnion<PT1, PT2> &ptr) {
|
|
return hash_value(ptr.getOpaqueValue());
|
|
}
|
|
}
|
|
|
|
namespace swift {
|
|
|
|
/// Stores a value of any type that satisfies a small set of requirements.
|
|
///
|
|
/// Requirements on the values stored within an AnyValue:
|
|
///
|
|
/// - Copy constructor
|
|
/// - Equality operator (==)
|
|
/// - TypeID support (see swift/Basic/TypeID.h)
|
|
/// - Display support (free function):
|
|
/// void simple_display(llvm::raw_ostream &, const T &);
|
|
class AnyValue {
|
|
/// Abstract base class used to hold on to a value.
|
|
class HolderBase {
|
|
public:
|
|
/// Type ID number.
|
|
const uint64_t typeID;
|
|
|
|
HolderBase() = delete;
|
|
HolderBase(const HolderBase &) = delete;
|
|
HolderBase(HolderBase &&) = delete;
|
|
HolderBase &operator=(const HolderBase &) = delete;
|
|
HolderBase &operator=(HolderBase &&) = delete;
|
|
|
|
/// Initialize base with type ID.
|
|
HolderBase(uint64_t typeID) : typeID(typeID) { }
|
|
|
|
virtual ~HolderBase();
|
|
|
|
/// Determine whether this value is equivalent to another.
|
|
///
|
|
/// The caller guarantees that the type IDs are the same.
|
|
virtual bool equals(const HolderBase &other) const = 0;
|
|
|
|
/// Display.
|
|
virtual void display(llvm::raw_ostream &out) const = 0;
|
|
};
|
|
|
|
/// Holds a value that can be used as a request input/output.
|
|
template<typename T>
|
|
class Holder final : public HolderBase {
|
|
public:
|
|
const T value;
|
|
|
|
Holder(T &&value)
|
|
: HolderBase(TypeID<T>::value),
|
|
value(std::move(value)) { }
|
|
|
|
Holder(const T &value) : HolderBase(TypeID<T>::value), value(value) { }
|
|
|
|
virtual ~Holder() { }
|
|
|
|
/// Determine whether this value is equivalent to another.
|
|
///
|
|
/// The caller guarantees that the type IDs are the same.
|
|
virtual bool equals(const HolderBase &other) const override {
|
|
assert(typeID == other.typeID && "Caller should match type IDs");
|
|
return value == static_cast<const Holder<T> &>(other).value;
|
|
}
|
|
|
|
/// Display.
|
|
virtual void display(llvm::raw_ostream &out) const override {
|
|
simple_display(out, value);
|
|
}
|
|
};
|
|
|
|
/// The data stored in this value.
|
|
std::shared_ptr<HolderBase> stored;
|
|
|
|
public:
|
|
/// Construct a new instance with the given value.
|
|
template<typename T>
|
|
AnyValue(T&& value) {
|
|
using ValueType = typename std::remove_reference<T>::type;
|
|
stored.reset(new Holder<ValueType>(std::forward<T>(value)));
|
|
}
|
|
|
|
/// Cast to a specific (known) type.
|
|
template<typename T>
|
|
const T &castTo() const {
|
|
assert(stored->typeID == TypeID<T>::value);
|
|
return static_cast<const Holder<T> *>(stored.get())->value;
|
|
}
|
|
|
|
/// Try casting to a specific (known) type, returning \c nullptr on
|
|
/// failure.
|
|
template<typename T>
|
|
const T *getAs() const {
|
|
if (stored->typeID != TypeID<T>::value)
|
|
return nullptr;
|
|
|
|
return &static_cast<const Holder<T> *>(stored.get())->value;
|
|
}
|
|
|
|
/// Compare two instances for equality.
|
|
friend bool operator==(const AnyValue &lhs, const AnyValue &rhs) {
|
|
if (lhs.stored->typeID != rhs.stored->typeID)
|
|
return false;
|
|
|
|
return lhs.stored->equals(*rhs.stored);
|
|
}
|
|
|
|
friend bool operator!=(const AnyValue &lhs, const AnyValue &rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
friend void simple_display(llvm::raw_ostream &out, const AnyValue &value) {
|
|
value.stored->display(out);
|
|
}
|
|
|
|
/// Return the result of calling simple_display as a string.
|
|
std::string getAsString() const;
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
namespace llvm {
|
|
template<typename T>
|
|
bool operator==(const TinyPtrVector<T> &lhs, const TinyPtrVector<T> &rhs) {
|
|
if (lhs.size() != rhs.size())
|
|
return false;
|
|
|
|
for (unsigned i = 0, n = lhs.size(); i != n; ++i) {
|
|
if (lhs[i] != rhs[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template<typename T>
|
|
bool operator!=(const TinyPtrVector<T> &lhs, const TinyPtrVector<T> &rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
template<typename T>
|
|
void simple_display(raw_ostream &out, const Optional<T> &opt) {
|
|
if (opt) {
|
|
simple_display(out, *opt);
|
|
}
|
|
out << "None";
|
|
}
|
|
} // end namespace llvm
|
|
|
|
#endif //
|
|
|
|
|