Skip to content

[AST] Fix canonicalization of the function input types #12304

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 6, 2017
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
42 changes: 26 additions & 16 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,27 @@ void ProtocolType::canonicalizeProtocols(
llvm::array_pod_sort(protocols.begin(), protocols.end(), compareProtocols);
}

static Type
getCanonicalInputType(AnyFunctionType *funcType,
llvm::function_ref<CanType(Type)> getCanonicalType) {
auto origInputType = funcType->getInput();
bool isParen = isa<ParenType>(origInputType.getPointer());
Type inputType = getCanonicalType(origInputType);

if (!isParen && AnyFunctionType::isCanonicalFunctionInputType(inputType))
return inputType;

auto flags = ParameterTypeFlags().withInOut(inputType->is<InOutType>());
if (auto *parenTy = dyn_cast<ParenType>(origInputType.getPointer()))
flags = flags.withShared(parenTy->getParameterFlags().isShared());

inputType = ParenType::get(inputType->getASTContext(),
inputType->getInOutObjectType(), flags);
assert(AnyFunctionType::isCanonicalFunctionInputType(inputType));

return inputType;
}

/// getCanonicalType - Return the canonical version of this type, which has
/// sugar from all levels stripped off.
CanType TypeBase::getCanonicalType() {
Expand Down Expand Up @@ -1124,15 +1145,10 @@ CanType TypeBase::getCanonicalType() {
// Transform the input and result types.
auto &ctx = function->getInput()->getASTContext();
auto &mod = *ctx.TheBuiltinModule;
Type inputTy = function->getInput()->getCanonicalType(sig, mod);
if (!AnyFunctionType::isCanonicalFunctionInputType(inputTy)) {
auto flags = ParameterTypeFlags().withInOut(inputTy->is<InOutType>());
if (auto parenTy = dyn_cast<ParenType>(function->getInput().getPointer()))
flags = flags.withShared(parenTy->getParameterFlags().isShared());
inputTy = ParenType::get(ctx, inputTy->getInOutObjectType(), flags);
}
auto inputTy = getCanonicalInputType(function, [&](Type type) -> CanType {
return type->getCanonicalType(sig, mod);
});
auto resultTy = function->getResult()->getCanonicalType(sig, mod);

Result = GenericFunctionType::get(sig, inputTy, resultTy,
function->getExtInfo());
assert(Result->isCanonical());
Expand All @@ -1146,14 +1162,8 @@ CanType TypeBase::getCanonicalType() {

case TypeKind::Function: {
FunctionType *FT = cast<FunctionType>(this);
Type In = FT->getInput()->getCanonicalType();
if (!AnyFunctionType::isCanonicalFunctionInputType(In)) {
auto flags = ParameterTypeFlags().withInOut(In->is<InOutType>());
if (auto parenTy = dyn_cast<ParenType>(FT->getInput().getPointer()))
flags = flags.withShared(parenTy->getParameterFlags().isShared());
In = ParenType::get(In->getASTContext(), In->getInOutObjectType(), flags);
assert(AnyFunctionType::isCanonicalFunctionInputType(In));
}
auto In = getCanonicalInputType(
FT, [](Type type) -> CanType { return type->getCanonicalType(); });
Type Out = FT->getResult()->getCanonicalType();
Result = FunctionType::get(In, Out, FT->getExtInfo());
break;
Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func f8<T:P2>(_ n: T, _ f: @escaping (T) -> T) {}
f8(3, f4) // expected-error {{in argument type '(Int) -> Int', 'Int' does not conform to expected type 'P2'}}
typealias Tup = (Int, Double)
func f9(_ x: Tup) -> Tup { return x }
f8((1,2.0), f9) // expected-error {{in argument type '(Tup) -> Tup' (aka '(Int, Double) -> (Int, Double)'), 'Tup' (aka '(Int, Double)') does not conform to expected type 'P2'}}
f8((1,2.0), f9) // expected-error {{in argument type '(Tup) -> Tup' (aka '((Int, Double)) -> (Int, Double)'), 'Tup' (aka '(Int, Double)') does not conform to expected type 'P2'}}

// <rdar://problem/19658691> QoI: Incorrect diagnostic for calling nonexistent members on literals
1.doesntExist(0) // expected-error {{value of type 'Int' has no member 'doesntExist'}}
Expand Down