Open BigZaphod opened 8 years ago
Reduced:
func test<T: Hashable>(check: (T, T) -> Bool = { $0 == $1 }) {}
@slavapestov, you've been working with generics a lot lately. Any ideas?
Comment by Myke Olson (JIRA)
@swift-ci create
This is weird, why do we have AnyHashable showing up here?
(function_conversion_expr implicit type='(T, T) -> Bool' location=def.swift:1:48 range=[def.swift:1:48 - line:1:59]
(closure_expr type='(AnyHashable, AnyHashable) -> Bool' location=def.swift:1:48 range=[def.swift:1:48 - line:1:59] discriminator=0 single-expression
(parameter_list
(parameter "$0" type='AnyHashable')
(parameter "$1" type='AnyHashable'))
(binary_expr type='Bool' location=def.swift:1:53 range=[def.swift:1:50 - line:1:56] nothrow
(dot_syntax_call_expr implicit type='(AnyHashable, AnyHashable) -> Bool' location=def.swift:1:53 range=[def.swift:1:53 - line:1:53] nothrow
(declref_expr type='(AnyHashable.Type) -> (AnyHashable, AnyHashable) -> Bool' location=def.swift:1:53 range=[def.swift:1:53 - line:1:53] decl=Swift.(file).AnyHashable.== function_ref=unapplied specialized=no)
(type_expr implicit type='AnyHashable.Type' location=def.swift:1:53 range=[def.swift:1:53 - line:1:53] typerepr='AnyHashable'))
(tuple_expr implicit type='(AnyHashable, AnyHashable)' location=def.swift:1:50 range=[def.swift:1:50 - line:1:56]
(declref_expr type='AnyHashable' location=def.swift:1:50 range=[def.swift:1:50 - line:1:50] decl=def.(file).func decl.default argument initializer.explicit closure discriminator=0.$0@def.swift:1:48 function_ref=unapplied specialized=no)
(declref_expr type='AnyHashable' location=def.swift:1:56 range=[def.swift:1:56 - line:1:56] decl=def.(file).func decl.default argument initializer.explicit closure discriminator=0.$1@def.swift:1:48 function_ref=unapplied specialized=no)))))
If I change 'T : Hashable' to 'T : Equatable', there's no problem, so there's some kind of 'erase type variable to AnyHashable' thing that's kicking in erroneously.
Here's the culprit in CSSimplify.cpp:
// T -> AnyHashable.
if (isAnyHashableType(desugar2)) {
// Don't allow this in operator contexts or we'll end up allowing
// 'T() == U()' for unrelated T and U that just happen to be Hashable.
// We can remove this special case when we implement operator hiding.
if (kind != ConstraintKind::OperatorArgumentConversion) {
conversionsOrFixes.push_back(
ConversionRestrictionKind::HashableToAnyHashable);
}
}
For some reason, we pick the AnyHashable:== overload, instead of Equatable:==, even though the former requires a conversion. We don't even consider Equatable:== at all.
@DougGregor or @rudkx any ideas?
This has nothing to do with default arguments either:
func test<T : Hashable>(t: T) {
let check: (T, T) -> Bool = { $0 == $1 }
}
This works, but if I omit the type annotations on x and y, it fails:
func test<T : Hashable>(t: T) -> Bool {
let check: (T, T) -> Bool = { (x: T, y: T) in x == y }
}
So when we're inferring argument types for the closure, we prefer non-generic ones for some reason?
So I realized there really is a bug here, SILGen needs to be able to emit a archetype to AnyHashable erasure, because you can request one with a function cast. However, the other issue in overload resolution is still worth investigating.
Attachment: Download
Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug, 3.0Regression, CompilerCrash | |Assignee | None | |Priority | Medium | md5: 920e64667a2bdec078d83b2a065cd016Issue Description:
I get the following crash in the Xcode 8 GM (which did not occur in prior Xcode betas):