Skip to content

[SE-0101] Migration support fix-it #3883

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 2 commits into from
Jul 30, 2016
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
83 changes: 82 additions & 1 deletion lib/Sema/MiscDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "swift/Parse/Lexer.h"
#include "swift/Parse/Parser.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace swift;

Expand Down Expand Up @@ -1810,6 +1811,9 @@ class AvailabilityWalker : public ASTWalker {
const ApplyExpr *call = nullptr);
bool diagnoseIncDecRemoval(const ValueDecl *D, SourceRange R,
const AvailableAttr *Attr);
bool diagnoseMemoryLayoutMigration(const ValueDecl *D, SourceRange R,
const AvailableAttr *Attr,
const ApplyExpr *call);

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

if (auto *attr = AvailableAttr::isUnavailable(D))
if (auto *attr = AvailableAttr::isUnavailable(D)) {
if (diagnoseIncDecRemoval(D, R, attr))
return true;
if (call && diagnoseMemoryLayoutMigration(D, R, attr, call))
return true;
}

if (TC.diagnoseExplicitUnavailability(D, R, DC, call))
return true;
Expand Down Expand Up @@ -2050,7 +2057,81 @@ bool AvailabilityWalker::diagnoseIncDecRemoval(const ValueDecl *D,
return false;
}

/// If this is a call to an unavailable sizeof family functions, diagnose it
/// with a fixit hint and return true. If not, or if we fail, return false.
bool AvailabilityWalker::diagnoseMemoryLayoutMigration(const ValueDecl *D,
SourceRange R,
const AvailableAttr *Attr,
const ApplyExpr *call) {

if (!D->getModuleContext()->isStdlibModule())
return false;

std::pair<StringRef, bool> KindValue
= llvm::StringSwitch<std::pair<StringRef, bool>>(D->getNameStr())
.Case("sizeof", {"size", false})
.Case("alignof", {"alignment", false})
.Case("strideof", {"stride", false})
.Case("sizeofValue", {"size", true})
.Case("alignofValue", {"alignment", true})
.Case("strideofValue", {"stride", true})
.Default({});

if (KindValue.first.empty())
return false;

auto Kind = KindValue.first;
auto isValue = KindValue.second;

auto args = dyn_cast<ParenExpr>(call->getArg());
if (!args)
return false;

auto subject = args->getSubExpr();
if (!isValue) {
// sizeof(x.dynamicType) is equivalent to sizeofValue(x)
if (auto DTE = dyn_cast<DynamicTypeExpr>(subject)) {
subject = DTE->getBase();
isValue = true;
}
}

EncodedDiagnosticMessage EncodedMessage(Attr->Message);
auto diag = TC.diagnose(R.Start, diag::availability_decl_unavailable_msg,
D->getFullName(), EncodedMessage.Message);
diag.highlight(R);

StringRef Prefix = "MemoryLayout<";
StringRef Suffix = ">.";
if (isValue) {
auto valueType = subject->getType()->getRValueType();
if (!valueType || valueType->is<ErrorType>()) {
// If we dont have good argument, We cannot emit fix-it.
return true;
}

// NOTE: We are destructively replacing the source text here.
// For instance, `sizeof(x.doSomethig())` => `MemoryLayout<T>.size` where
// T is return type of `doSomething()`. If that function have any
// side effects, it will break the source.
diag.fixItReplace(call->getSourceRange(),
(Prefix + valueType->getString() + Suffix + Kind).str());
} else {
SourceRange PrefixRange(call->getStartLoc(), args->getLParenLoc());
SourceRange SuffixRange(args->getRParenLoc());

// We must truncate `.self`.
// E.g. sizeof(T.self) => MemoryLayout<T>.size
if (auto *DSE = dyn_cast<DotSelfExpr>(subject))
SuffixRange.Start = DSE->getDotLoc();

diag
.fixItReplace(PrefixRange, Prefix)
.fixItReplace(SuffixRange, (Suffix + Kind).str());
}

return true;
}

/// Diagnose uses of unavailable declarations.
static void diagAvailability(TypeChecker &TC, const Expr *E,
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/SDK/Dispatch/Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {

/// Copy the contents of the data into a buffer.
///
/// 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.
/// 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.
/// - precondition: The range must be within the bounds of the data. Otherwise `fatalError` is called.
/// - parameter buffer: A buffer to copy the data into.
/// - 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.
Expand Down
9 changes: 9 additions & 0 deletions test/1_stdlib/Renames.swift
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,15 @@ func _Map<C : Collection>(c: C) {
_ = LazyMapCollection(c) { _ in true } // expected-error {{'init(_:transform:)' is unavailable: use '.lazy.map' on the collection}} {{none}}
}

func _MemoryLayout<T>(t: T) {
_ = sizeof(T.self) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{15-21=>.size}} {{none}}
_ = alignof(T.self) // expected-error {{'alignof' is unavailable: use MemoryLayout<T>.alignment instead.}} {{7-15=MemoryLayout<}} {{16-22=>.alignment}} {{none}}
_ = strideof(T.self) // expected-error {{'strideof' is unavailable: use MemoryLayout<T>.stride instead.}} {{7-16=MemoryLayout<}} {{17-23=>.stride}} {{none}}
_ = sizeofValue(t) // expected-error {{'sizeofValue' is unavailable: use MemoryLayout<T>.size instead.}} {{7-21=MemoryLayout<T>.size}} {{none}}
_ = alignofValue(t) // expected-error {{'alignofValue' is unavailable: use MemoryLayout<T>.alignment instead.}} {{7-22=MemoryLayout<T>.alignment}} {{none}}
_ = strideofValue(t) // expected-error {{'strideofValue' is unavailable: use MemoryLayout<T>.stride instead.}} {{7-23=MemoryLayout<T>.stride}} {{none}}
}

func _Mirror() {
func fn<M : MirrorPathType>(_: M) {} // expected-error {{'MirrorPathType' has been renamed to 'MirrorPath'}} {{15-29=MirrorPath}} {{none}}
}
Expand Down
27 changes: 27 additions & 0 deletions test/expr/expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -872,3 +872,30 @@ let _ = (x, 3).1
(x,y).1 = 7 // expected-error {{cannot assign to immutable expression of type 'Int'}}
x = (x,(3,y)).1.1


// SE-0101 sizeof family functions are reconfigured into MemoryLayout
protocol Pse0101 {
associatedtype Value
func getIt() -> Value
}
class Cse0101<U> {
typealias T = U
var val: U { fatalError() }
}
func se0101<P: Pse0101>(x: Cse0101<P>) {
// Note: The first case is actually not allowed, but it is very common and can be compiled currently.
_ = sizeof(P) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{15-16=>.size}} {{none}}
// expected-warning@-1 {{missing '.self' for reference to metatype of type 'P'}}
_ = sizeof(P.self) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{15-21=>.size}} {{none}}
_ = sizeof(P.Value.self) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{21-27=>.size}} {{none}}
_ = sizeof(Cse0101<P>.self) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-14=MemoryLayout<}} {{24-30=>.size}} {{none}}
_ = alignof(Cse0101<P>.T.self) // expected-error {{'alignof' is unavailable: use MemoryLayout<T>.alignment instead.}} {{7-15=MemoryLayout<}} {{27-33=>.alignment}} {{none}}
_ = strideof(P.Type.self) // expected-error {{'strideof' is unavailable: use MemoryLayout<T>.stride instead.}} {{7-16=MemoryLayout<}} {{22-28=>.stride}} {{none}}
_ = sizeof(type(of: x)) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-26=MemoryLayout<Cse0101<P>>.size}} {{none}}/
_ = sizeof(x.dynamicType) // expected-error {{'sizeof' is unavailable: use MemoryLayout<T>.size instead.}} {{7-28=MemoryLayout<Cse0101<P>>.size}} {{none}}
// expected-warning@-1 {{'.dynamicType' is deprecated. Use 'type(of: ...)' instead}}

_ = sizeofValue(x) // expected-error {{'sizeofValue' is unavailable: use MemoryLayout<T>.size instead.}} {{7-21=MemoryLayout<Cse0101<P>>.size}} {{none}}
_ = alignofValue(x.val) // expected-error {{'alignofValue' is unavailable: use MemoryLayout<T>.alignment instead.}} {{7-26=MemoryLayout<P>.alignment}} {{none}}
_ = strideofValue(x.val.getIt()) // expected-error {{'strideofValue' is unavailable: use MemoryLayout<T>.stride instead.}} {{7-35=MemoryLayout<P.Value>.stride}} {{none}}
}