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

Property behaviors prototype #1297

Closed
wants to merge 5 commits into
base: master
from

Conversation

Projects
None yet
2 participants
@jckarter
Member

jckarter commented Feb 13, 2016

Parse 'var [behavior] x: T', and when we see it, try to instantiate the property's
implementation in terms of the given behavior. To start out, behaviors are modeled
as protocols. If the protocol follows this pattern:

  protocol behavior {
    associatedtype Value
  }
  extension behavior {
    var value: Value { ... }
  }

then the property is instantiated by forming a conformance to behavior where
Self is bound to the enclosing type and Value is bound to the property's
declared type, and invoking the accessors of the value implementation:

  struct Foo {
    var [behavior] foo: Int
  }

  /* behaves like */

  extension Foo: private behavior {
    @implements(behavior.Value)
    private typealias `[behavior].Value` = Int

    var foo: Int {
      get { return value }
      set { value = newValue }
    }
  }

If the protocol requires a storage member, and provides an initStorage method
to provide an initial value to the storage:

  protocol storageBehavior {
    associatedtype Value

    var storage: Something<Value> { ... }
  }
  extension storageBehavior {
    var value: Value { ... }

    static func initStorage() -> Something<Value> { ... }
  }

then a stored property of the appropriate type is instantiated to witness the
requirement, using initStorage to initialize:

  struct Foo {
    var [storageBehavior] foo: Int
  }

  /* behaves like */

  extension Foo: private storageBehavior {
    @implements(storageBehavior.Value)
    private typealias `[storageBehavior].Value` = Int
    @implements(storageBehavior.storage)
    private var `[storageBehavior].storage`: Something<Int> = initStorage()

    var foo: Int {
      get { return value }
      set { value = newValue }
    }
  }

In either case, the value and storage properties should support any combination
of get-only/settable and mutating/nonmutating modifiers. The instantiated property
follows the settability and mutating-ness of the value implementation. The
protocol can also impose requirements on the Self and Value types.

Bells and whistles such as initializer expressions, accessors,
out-of-line initialization, etc. are not implemented. Additionally, behaviors
that instantiate storage are currently only supported on instance properties.
This also hasn't been tested past sema yet; SIL and IRGen will likely expose
additional issues.

@jckarter

This comment has been minimized.

Show comment
Hide comment
@jckarter

jckarter Feb 13, 2016

Member

@swift-ci Please test

Member

jckarter commented Feb 13, 2016

@swift-ci Please test

1 similar comment
@jckarter

This comment has been minimized.

Show comment
Hide comment
@jckarter

jckarter Feb 13, 2016

Member

@swift-ci Please test

Member

jckarter commented Feb 13, 2016

@swift-ci Please test

@@ -3626,7 +3647,7 @@ class AbstractStorageDecl : public ValueDecl {
}
};
void configureAddressorRecord(AddressorRecord *record,
FuncDecl *addressor, FuncDecl *mutableAddressor);
FuncDecl *addressor, FuncDecl *mutableAddressor);

This comment has been minimized.

@slavapestov

slavapestov Feb 15, 2016

Member

Pointless edit here?

@slavapestov

slavapestov Feb 15, 2016

Member

Pointless edit here?

This comment has been minimized.

@jckarter

jckarter Feb 15, 2016

Member

Fixing an 80-column violation.

@jckarter

jckarter Feb 15, 2016

Member

Fixing an 80-column violation.

@slavapestov

View changes

Show outdated Hide outdated lib/AST/Decl.cpp Outdated
@slavapestov

View changes

Show outdated Hide outdated lib/Sema/CodeSynthesis.cpp Outdated
@slavapestov

View changes

Show outdated Hide outdated lib/Sema/CodeSynthesis.cpp Outdated
@slavapestov

View changes

Show outdated Hide outdated lib/Sema/CodeSynthesis.cpp Outdated
@slavapestov

View changes

Show outdated Hide outdated lib/Sema/CodeSynthesis.cpp Outdated
@@ -1332,6 +1685,10 @@ void swift::maybeAddAccessorsToVariable(VarDecl *var, TypeChecker &TC) {
return;
}
// Local variables don't otherwise get accessors.
if (var->getDeclContext()->isLocalContext())

This comment has been minimized.

@slavapestov

slavapestov Feb 15, 2016

Member

Was there a test case for this fix?

@slavapestov

slavapestov Feb 15, 2016

Member

Was there a test case for this fix?

This comment has been minimized.

@jckarter

jckarter Feb 15, 2016

Member

I test some local vars with behaviors, yeah. We ban lazy in local contexts so it doesn't yet matter in trunk.

@jckarter

jckarter Feb 15, 2016

Member

I test some local vars with behaviors, yeah. We ban lazy in local contexts so it doesn't yet matter in trunk.

@slavapestov

View changes

Show outdated Hide outdated lib/Sema/TypeCheckDecl.cpp Outdated
} else {
llvm_unreachable("unknown type context type?!");
}
bool conforms = TC.conformsToProtocol(behaviorSelf, refinedProto, dc,

This comment has been minimized.

@slavapestov

slavapestov Feb 15, 2016

Member

Indentation

@slavapestov

slavapestov Feb 15, 2016

Member

Indentation

auto sig = behaviorProto->getGenericSignatureOfContext();
auto map = sig->getSubstitutionMap(interfaceSubs);
auto substValueTy = behavior->ValueDecl->getInterfaceType()
.subst(decl->getModuleContext(), map, SubstOptions());

This comment has been minimized.

@slavapestov

slavapestov Feb 15, 2016

Member

I think SubstOptions are a default parameter?

@slavapestov

slavapestov Feb 15, 2016

Member

I think SubstOptions are a default parameter?

This comment has been minimized.

@jckarter

jckarter Feb 15, 2016

Member

Doesn't seem to be. I was just following Xcode code completion, which swallows defaulted args.

@jckarter

jckarter Feb 15, 2016

Member

Doesn't seem to be. I was just following Xcode code completion, which swallows defaulted args.

@slavapestov

View changes

Show outdated Hide outdated test/decl/var/behaviors.swift Outdated
@slavapestov

This comment has been minimized.

Show comment
Hide comment
@slavapestov

slavapestov Feb 15, 2016

Member

@jckarter This looks awesome. I just have a few nitpicks that you're free to ignore.

Member

slavapestov commented Feb 15, 2016

@jckarter This looks awesome. I just have a few nitpicks that you're free to ignore.

@jckarter

This comment has been minimized.

Show comment
Hide comment
@jckarter

jckarter Feb 17, 2016

Member

@swift-ci Please test

Member

jckarter commented Feb 17, 2016

@swift-ci Please test

1 similar comment
@jckarter

This comment has been minimized.

Show comment
Hide comment
@jckarter

jckarter Feb 17, 2016

Member

@swift-ci Please test

Member

jckarter commented Feb 17, 2016

@swift-ci Please test

jckarter added some commits Jan 28, 2016

Sema: Initial parsing and synthesis for properties with behaviors.
Parse 'var [behavior] x: T', and when we see it, try to instantiate the property's
implementation in terms of the given behavior. To start out, behaviors are modeled
as protocols. If the protocol follows this pattern:

  ```
  protocol behavior {
    associatedtype Value
  }
  extension behavior {
    var value: Value { ... }
  }
  ```

then the property is instantiated by forming a conformance to `behavior` where
`Self` is bound to the enclosing type and `Value` is bound to the property's
declared type, and invoking the accessors of the `value` implementation:

  ```
  struct Foo {
    var [behavior] foo: Int
  }

  /* behaves like */

  extension Foo: private behavior {
    @implements(behavior.Value)
    private typealias `[behavior].Value` = Int

    var foo: Int {
      get { return value }
      set { value = newValue }
    }
  }
  ```

If the protocol requires a `storage` member, and provides an `initStorage` method
to provide an initial value to the storage:

  ```
  protocol storageBehavior {
    associatedtype Value

    var storage: Something<Value> { ... }
  }
  extension storageBehavior {
    var value: Value { ... }

    static func initStorage() -> Something<Value> { ... }
  }
  ```

then a stored property of the appropriate type is instantiated to witness the
requirement, using `initStorage` to initialize:

  ```
  struct Foo {
    var [storageBehavior] foo: Int
  }

  /* behaves like */

  extension Foo: private storageBehavior {
    @implements(storageBehavior.Value)
    private typealias `[storageBehavior].Value` = Int
    @implements(storageBehavior.storage)
    private var `[storageBehavior].storage`: Something<Int> = initStorage()

    var foo: Int {
      get { return value }
      set { value = newValue }
    }
  }
  ```

In either case, the `value` and `storage` properties should support any combination
of get-only/settable and mutating/nonmutating modifiers. The instantiated property
follows the settability and mutating-ness of the `value` implementation. The
protocol can also impose requirements on the `Self` and `Value` types.

Bells and whistles such as initializer expressions, accessors,
out-of-line initialization, etc. are not implemented. Additionally, behaviors
that instantiate storage are currently only supported on instance properties.
This also hasn't been tested past sema yet; SIL and IRGen will likely expose
additional issues.
Sema/SILGen: Get property behavior implementations to codegen.
Fix some interface type/context type confusion in the AST synthesis from the previous patch, add a unique private mangling for behavior protocol conformances, and set up SILGen to emit the conformances when property declarations with behaviors are visited. Disable synthesis of the struct memberwise initializer if any instance properties use behaviors; codegen will need to be redesigned here.
Add an interpreter test for "delayed" property behavior.
We have enough implementation to do "delayed" now.

@jckarter jckarter changed the title from Sema: Initial parsing and synthesis for properties with behaviors. to Property behaviors prototype Feb 19, 2016

@jckarter

This comment has been minimized.

Show comment
Hide comment
@jckarter

jckarter Feb 19, 2016

Member

@swift-ci Please test

Member

jckarter commented Feb 19, 2016

@swift-ci Please test

jckarter added some commits Feb 17, 2016

Sema: Fix crash when behavior protocol is missing `initStorage` requi…
…rement.

Would be nice to have `guard` in C++...
Conditionally enable behaviors by a frontend flag.
Since the feature is incomplete and yet to be accepted or implemented as proposed, hide it behind an -enable-experimental-property-behaviors frontend flag.
@jckarter

This comment has been minimized.

Show comment
Hide comment
@jckarter

jckarter Feb 19, 2016

Member

@swift-ci Please test

Member

jckarter commented Feb 19, 2016

@swift-ci Please test

@jckarter

This comment has been minimized.

Show comment
Hide comment
@jckarter

jckarter Feb 20, 2016

Member

I've merged this into master, hidden behind a frontend flag, -enable-experimental-property-behaviors.

Member

jckarter commented Feb 20, 2016

I've merged this into master, hidden behind a frontend flag, -enable-experimental-property-behaviors.

@jckarter jckarter closed this Feb 21, 2016

@jckarter jckarter deleted the jckarter:property-behaviors branch Feb 21, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment