Commits

Slava Pestov committed 6812b6926b9
Sema: Cleanups and minor fixes for protocol 'Self' types We had four duplicated implementations of checking how a protocol requirement uses 'Self', all slightly wrong or incomplete: - When deciding if the protocol type can be used as an existential. This one would just ignore 'Self' in the return type of a method completely, which was incorrect for cases where 'Self' is contravariant but part of the return value, for example: func foo() -> (Self -> ()) - When deciding if a member access can be performed on an existential value. This is distinct from the former, because the member may have been defined in a protocol extension, in which case it cannot be used even if the protocol type can be used as an existential. Unfortunately, this implementation was overly conservative, and would reject uses of 'Self' where Sema could in fact erase the existential type, for example: func foo() -> Self?? func foo() -> Self.Type func foo() -> (Self, Self) This function handled function return types correctly, effectively plugging the leak in the previous code. It did lead to inconsistent behavior with protocols that had contravariant Self in requirements though; sometimes we would diagnose uses of the existential type, other times we would only complain about specific members. - When deciding if a method in a non-final class can model a protocol requirement. This one was the most elaborate one, but here contravariance and uses of associated types are actually okay, so it was written to pick up covariant 'Self' only. However, it also did not handle metatypes and tuples. - When opening the type of member of an existential, we would check if the return value was 'Self' or an optional of 'Self', but again this check was too conservative, so after the previous three were fixed, we could reference members on existentials that did not have a correct opened type. Now, these have been combined into one check. To fix some crashes, Sema's implementation of erasing existentials now relies on coerceToType() instead of hand-rolling a few coercions of its own, and wrapping the rest in CovariantFunctionConversionExpr, which didn't make much sense if the result was not a function type. SILGen still does not support function type conversions where an existential return value is being erased; these would silently miscompile before, but crash with an assertion now, because they are correctly modeled as a FunctionConversionExpr, and not CovariantFunctionConversionExpr.