Skip to content

Commit aee7a8b

Browse files
authored
Merge pull request #3883 from rintaro/SE-0101-migration-fixit
[SE-0101] Migration support fix-it
2 parents 1c58315 + fd4ddd6 commit aee7a8b

File tree

4 files changed

+119
-2
lines changed

4 files changed

+119
-2
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/Parse/Lexer.h"
2626
#include "swift/Parse/Parser.h"
2727
#include "llvm/ADT/MapVector.h"
28+
#include "llvm/ADT/StringSwitch.h"
2829
#include "llvm/Support/SaveAndRestore.h"
2930
using namespace swift;
3031

@@ -1810,6 +1811,9 @@ class AvailabilityWalker : public ASTWalker {
18101811
const ApplyExpr *call = nullptr);
18111812
bool diagnoseIncDecRemoval(const ValueDecl *D, SourceRange R,
18121813
const AvailableAttr *Attr);
1814+
bool diagnoseMemoryLayoutMigration(const ValueDecl *D, SourceRange R,
1815+
const AvailableAttr *Attr,
1816+
const ApplyExpr *call);
18131817

18141818
/// Walks up from a potential callee to the enclosing ApplyExpr.
18151819
const ApplyExpr *getEnclosingApplyExpr() const {
@@ -1948,9 +1952,12 @@ bool AvailabilityWalker::diagAvailability(const ValueDecl *D, SourceRange R,
19481952
if (!D)
19491953
return false;
19501954

1951-
if (auto *attr = AvailableAttr::isUnavailable(D))
1955+
if (auto *attr = AvailableAttr::isUnavailable(D)) {
19521956
if (diagnoseIncDecRemoval(D, R, attr))
19531957
return true;
1958+
if (call && diagnoseMemoryLayoutMigration(D, R, attr, call))
1959+
return true;
1960+
}
19541961

19551962
if (TC.diagnoseExplicitUnavailability(D, R, DC, call))
19561963
return true;
@@ -2050,7 +2057,81 @@ bool AvailabilityWalker::diagnoseIncDecRemoval(const ValueDecl *D,
20502057
return false;
20512058
}
20522059

2060+
/// If this is a call to an unavailable sizeof family functions, diagnose it
2061+
/// with a fixit hint and return true. If not, or if we fail, return false.
2062+
bool AvailabilityWalker::diagnoseMemoryLayoutMigration(const ValueDecl *D,
2063+
SourceRange R,
2064+
const AvailableAttr *Attr,
2065+
const ApplyExpr *call) {
2066+
2067+
if (!D->getModuleContext()->isStdlibModule())
2068+
return false;
2069+
2070+
std::pair<StringRef, bool> KindValue
2071+
= llvm::StringSwitch<std::pair<StringRef, bool>>(D->getNameStr())
2072+
.Case("sizeof", {"size", false})
2073+
.Case("alignof", {"alignment", false})
2074+
.Case("strideof", {"stride", false})
2075+
.Case("sizeofValue", {"size", true})
2076+
.Case("alignofValue", {"alignment", true})
2077+
.Case("strideofValue", {"stride", true})
2078+
.Default({});
2079+
2080+
if (KindValue.first.empty())
2081+
return false;
2082+
2083+
auto Kind = KindValue.first;
2084+
auto isValue = KindValue.second;
20532085

2086+
auto args = dyn_cast<ParenExpr>(call->getArg());
2087+
if (!args)
2088+
return false;
2089+
2090+
auto subject = args->getSubExpr();
2091+
if (!isValue) {
2092+
// sizeof(x.dynamicType) is equivalent to sizeofValue(x)
2093+
if (auto DTE = dyn_cast<DynamicTypeExpr>(subject)) {
2094+
subject = DTE->getBase();
2095+
isValue = true;
2096+
}
2097+
}
2098+
2099+
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
2100+
auto diag = TC.diagnose(R.Start, diag::availability_decl_unavailable_msg,
2101+
D->getFullName(), EncodedMessage.Message);
2102+
diag.highlight(R);
2103+
2104+
StringRef Prefix = "MemoryLayout<";
2105+
StringRef Suffix = ">.";
2106+
if (isValue) {
2107+
auto valueType = subject->getType()->getRValueType();
2108+
if (!valueType || valueType->is<ErrorType>()) {
2109+
// If we dont have good argument, We cannot emit fix-it.
2110+
return true;
2111+
}
2112+
2113+
// NOTE: We are destructively replacing the source text here.
2114+
// For instance, `sizeof(x.doSomethig())` => `MemoryLayout<T>.size` where
2115+
// T is return type of `doSomething()`. If that function have any
2116+
// side effects, it will break the source.
2117+
diag.fixItReplace(call->getSourceRange(),
2118+
(Prefix + valueType->getString() + Suffix + Kind).str());
2119+
} else {
2120+
SourceRange PrefixRange(call->getStartLoc(), args->getLParenLoc());
2121+
SourceRange SuffixRange(args->getRParenLoc());
2122+
2123+
// We must truncate `.self`.
2124+
// E.g. sizeof(T.self) => MemoryLayout<T>.size
2125+
if (auto *DSE = dyn_cast<DotSelfExpr>(subject))
2126+
SuffixRange.Start = DSE->getDotLoc();
2127+
2128+
diag
2129+
.fixItReplace(PrefixRange, Prefix)
2130+
.fixItReplace(SuffixRange, (Suffix + Kind).str());
2131+
}
2132+
2133+
return true;
2134+
}
20542135

20552136
/// Diagnose uses of unavailable declarations.
20562137
static void diagAvailability(TypeChecker &TC, const Expr *E,

stdlib/public/SDK/Dispatch/Data.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
149149

150150
/// Copy the contents of the data into a buffer.
151151
///
152-
/// This function copies the bytes in `range` from the data into the buffer. If the count of the `range` is greater than `MemoryLayout<DestinationType>.size * buffer.count` then the first N bytes will be copied into the buffer.
152+
/// This function copies the bytes in `range` from the data into the buffer. If the count of the `range` is greater than `MemoryLayout<DestinationType>.stride * buffer.count` then the first N bytes will be copied into the buffer.
153153
/// - precondition: The range must be within the bounds of the data. Otherwise `fatalError` is called.
154154
/// - parameter buffer: A buffer to copy the data into.
155155
/// - parameter range: A range in the data to copy into the buffer. If the range is empty, this function will return 0 without copying anything. If the range is nil, as much data as will fit into `buffer` is copied.

test/1_stdlib/Renames.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,15 @@ func _Map<C : Collection>(c: C) {
280280
_ = LazyMapCollection(c) { _ in true } // expected-error {{'init(_:transform:)' is unavailable: use '.lazy.map' on the collection}} {{none}}
281281
}
282282

283+
func _MemoryLayout<T>(t: T) {
284+
_ = sizeof(T.self) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{15-21=>.size}} {{none}}
285+
_ = alignof(T.self) // expected-error {{'alignof' is unavailable: use MemoryLayout<T>.alignment instead.}} {{7-15=MemoryLayout<}} {{16-22=>.alignment}} {{none}}
286+
_ = strideof(T.self) // expected-error {{'strideof' is unavailable: use MemoryLayout<T>.stride instead.}} {{7-16=MemoryLayout<}} {{17-23=>.stride}} {{none}}
287+
_ = sizeofValue(t) // expected-error {{'sizeofValue' is unavailable: use MemoryLayout<T>.size instead.}} {{7-21=MemoryLayout<T>.size}} {{none}}
288+
_ = alignofValue(t) // expected-error {{'alignofValue' is unavailable: use MemoryLayout<T>.alignment instead.}} {{7-22=MemoryLayout<T>.alignment}} {{none}}
289+
_ = strideofValue(t) // expected-error {{'strideofValue' is unavailable: use MemoryLayout<T>.stride instead.}} {{7-23=MemoryLayout<T>.stride}} {{none}}
290+
}
291+
283292
func _Mirror() {
284293
func fn<M : MirrorPathType>(_: M) {} // expected-error {{'MirrorPathType' has been renamed to 'MirrorPath'}} {{15-29=MirrorPath}} {{none}}
285294
}

test/expr/expressions.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,3 +872,30 @@ let _ = (x, 3).1
872872
(x,y).1 = 7 // expected-error {{cannot assign to immutable expression of type 'Int'}}
873873
x = (x,(3,y)).1.1
874874

875+
876+
// SE-0101 sizeof family functions are reconfigured into MemoryLayout
877+
protocol Pse0101 {
878+
associatedtype Value
879+
func getIt() -> Value
880+
}
881+
class Cse0101<U> {
882+
typealias T = U
883+
var val: U { fatalError() }
884+
}
885+
func se0101<P: Pse0101>(x: Cse0101<P>) {
886+
// Note: The first case is actually not allowed, but it is very common and can be compiled currently.
887+
_ = sizeof(P) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{15-16=>.size}} {{none}}
888+
// expected-warning@-1 {{missing '.self' for reference to metatype of type 'P'}}
889+
_ = sizeof(P.self) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{15-21=>.size}} {{none}}
890+
_ = sizeof(P.Value.self) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{21-27=>.size}} {{none}}
891+
_ = sizeof(Cse0101<P>.self) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{24-30=>.size}} {{none}}
892+
_ = alignof(Cse0101<P>.T.self) // expected-error {{'alignof' is unavailable: use MemoryLayout<T>.alignment instead.}} {{7-15=MemoryLayout<}} {{27-33=>.alignment}} {{none}}
893+
_ = strideof(P.Type.self) // expected-error {{'strideof' is unavailable: use MemoryLayout<T>.stride instead.}} {{7-16=MemoryLayout<}} {{22-28=>.stride}} {{none}}
894+
_ = sizeof(type(of: x)) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-26=MemoryLayout<Cse0101<P>>.size}} {{none}}/
895+
_ = sizeof(x.dynamicType) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-28=MemoryLayout<Cse0101<P>>.size}} {{none}}
896+
// expected-warning@-1 {{'.dynamicType' is deprecated. Use 'type(of: ...)' instead}}
897+
898+
_ = sizeofValue(x) // expected-error {{'sizeofValue' is unavailable: use MemoryLayout<T>.size instead.}} {{7-21=MemoryLayout<Cse0101<P>>.size}} {{none}}
899+
_ = alignofValue(x.val) // expected-error {{'alignofValue' is unavailable: use MemoryLayout<T>.alignment instead.}} {{7-26=MemoryLayout<P>.alignment}} {{none}}
900+
_ = strideofValue(x.val.getIt()) // expected-error {{'strideofValue' is unavailable: use MemoryLayout<T>.stride instead.}} {{7-35=MemoryLayout<P.Value>.stride}} {{none}}
901+
}

0 commit comments

Comments
 (0)