Attributed placeholder types

I've had a chance to look back at implementing the rest of placeholder types, and I'm still having some trouble figuring out how to tackle attributes for placeholder types. Currently, we always have a fully-specified TypeRepr wherever a type attribute appears, so we can use the attributes to guide the resolution of the type. Indeed, in resolveAttributedType we have:

  // The type we're working with, in case we want to build it differently
  // based on the attributes we see.
  Type ty;

So I'm wondering if it even makes sense under the current model to have type attributes which get applied outside of the immediate type resolution context. We don't currently allow comparable situations, e.g.,

typealias T = () -> Int

let x: @convention(c) T = { 0 } // error: @convention attribute only applies to function types

So I suppose I'm looking for some guidance about:

  1. Whether the limitation with typealiases is due to a fundamental limitation of how attributes interact with type resolution, or just because no one has pursued adding that functionality yet, and
  2. If there's no fundamental limitation keeping us from "late binding" attributes to types, what the best approach might be in pursuing an implementation.

Any input is very much appreciated!

1 Like

cc @hborla, I know you had some thoughts on this at one point, would love to hear if you've come up with anything further!

I think that the @convention(_) attribute should not be thought of as an attribute, it is a type parameter with attribute-like syntax.

typealias T = () -> Int
// really T = FunctionType<Swift, (), Int>
typealias S = @convention(c) () -> Int
// really T = FunctionType<C, (), Int>

@convention(c) T // doesn't make sense

The distinction being that you can't really do typealias T<Repr> = @convention(Repr) () -> Int or similar because we don't support having generic parameters representing conventions.

I don't think this counts as a limitation, it's the case that @convention(c) A is ill-formed. Only syntax forms like @convention(c) (A...) -> B are well-formed. Same goes for throws and async. (A...) throws -> B is well-formed whereas T throws is not. However, throws and async happen to have syntax which doesn't suggest that something like "extracting a typealias" ought to work, whereas (unfortunately?) @convention does.

Given that this feature would be useful quite broadly, and the fact that function types with other conventions are used relatively rarely, I think it might be better to leave that as a future direction in case that is a limitation people run into frequently, instead of doing all the work up front. (Unless you have some other examples -- say property wrappers -- where this ability would be useful?)

4 Likes

Yeah I'm leaning towards leaving it as a future direction as well, especially since the global actors proposal is attacking the problem of attributed closures so that { @convention(c) in 0 } could maybe become well-formed down the road as suggested here.

2 Likes