Skip to content

Unified: Resolve accessor accesses in type inference - #22909

Open
hvitved wants to merge 3 commits into
github:mainfrom
hvitved:unified/type-inference-resolve-accessors
Open

hvitved wants to merge 3 commits into
github:mainfrom
hvitved:unified/type-inference-resolve-accessors

Conversation

@hvitved

@hvitved hvitved commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Calls to function-valued computed properties incorrectly include accessor targets and add the property's Function type to the inferred call result.

5 open issues
What changed in this PR

Extends Unified’s type inference to resolve Swift property getters and setters alongside stored fields.

Changes:

  • Adds accessor-aware member lookup and read/write resolution.
  • Preserves backing-field bindings, unwraps modified types, and distinguishes getter/setter names.
  • Adds Swift accessor fixtures and updates type-inference expectations.
File Description
unified/​ql/​test/​library-tests/​type-inference/​type-inference.ql Checks accessor-resolution annotations.
unified/​ql/​test/​library-tests/​type-inference/​type-inference.expected Updates expected inferred types.
unified/​ql/​test/​library-tests/​type-inference/​accessors.swift Covers computed, observed, generic, inherited, and protocol properties.
unified/​ql/​lib/​codeql/​unified/​internal/​typeinference/​TypeMention.qll Resolves modified types through their underlying type.
unified/​ql/​lib/​codeql/​unified/​internal/​typeinference/​TypeInference.qll Models accessor fields and exposes accessor resolution.
unified/​ql/​lib/​codeql/​unified/​internal/​NameBindingPlugin.qll Includes accessors in instance-member classification.
unified/​ql/​lib/​codeql/​unified/​internal/​LocalNameBinding.qll Prefers backing fields over associated accessors.
unified/​ql/​lib/​codeql/​unified/​internal/​FacadeAst.qll Adds distinct getter and setter fallback names.

Review effort: Max

Comment thread unified/ql/lib/codeql/unified/internal/NameBindingPlugin.qll Outdated
Comment thread unified/ql/lib/codeql/unified/internal/NameBindingPlugin.qll Outdated
Comment thread unified/ql/lib/codeql/unified/internal/typeinference/TypeInference.qll Outdated
@hvitved
hvitved force-pushed the unified/type-inference-resolve-accessors branch from 06918fe to 16f5ce6 Compare October 28, 2026 08:28
@hvitved
hvitved requested a max review from Copilot October 28, 2026 08:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved Swift accessor defects lose static/class modifiers, confuse static and instance names, and miss inout setters and top-level/local accessor references, breaking resolution and type inference.

3 open issues
5 resolved since last review

Review effort: Max

Comment thread unified/extractor/src/languages/swift/swift.rs Outdated
Comment thread unified/ql/lib/codeql/unified/internal/LocalNameBinding.qll Outdated
Comment thread unified/ql/lib/codeql/unified/internal/typeinference/TypeInference.qll Outdated
@hvitved
hvitved force-pushed the unified/type-inference-resolve-accessors branch 2 times, most recently from adec24a to 7ef8de1 Compare October 28, 2026 09:23
@hvitved
hvitved requested a max review from Copilot October 28, 2026 09:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Computed properties passed as Swift inout arguments omit writeback setter resolution, while property observers can bypass the intended backing-field exclusion.

2 open issues
3 resolved since last review

Review effort: Max

Comment thread unified/ql/lib/codeql/unified/internal/LocalNameBinding.qll Outdated
Comment thread unified/ql/lib/codeql/unified/internal/typeinference/TypeInference.qll Outdated
@hvitved
hvitved force-pushed the unified/type-inference-resolve-accessors branch from 7ef8de1 to 27ba20a Compare October 28, 2026 09:48
@hvitved hvitved added the no-change-note-required This PR does not need a change note label Oct 28, 2026
@hvitved
hvitved marked this pull request as ready for review October 28, 2026 09:49
@hvitved
hvitved requested review from a team as code owners October 28, 2026 09:49
@hvitved
hvitved force-pushed the unified/type-inference-resolve-accessors branch from 27ba20a to 5b468f2 Compare October 29, 2026 10:52
@hvitved
hvitved requested a max review from Copilot October 29, 2026 10:52
class InheritedAccessors: GenericAccessors<Int> {
override var observed: Int {
didSet {
let current = observed // $ accessor=InheritedAccessors.observed $ MISSING: type=current:Int field=GenericAccessors.observed -- static name binding is currently unable to resolve the access to the backing field

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asgerf : Is this perhaps something you can look into?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Class-valued properties passed directly as inout lose setter dataflow, while incompatible shadowing keys cause stored properties to resolve to spurious inherited setter targets.

2 open issues
2 resolved since last review

Review effort: Max

Comment on lines +94 to +97
name = p.getExternalNameNode().getValue()
or
not exists(p.getExternalNameNode()) and
name = "_"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're OK with a spurious setter call

Comment on lines +20 to +21
// conservative value-type check
not forex(T::Type t | t = T::inferType(expr) | t.asClass().hasModifier("class"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense although I'd add a boolean parameter to isInWriteBackPosition to remember if it's in direct write-back position.

@asgerf asgerf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments otherwise LGTM 👍

}
var q: C {
get { C() }
set { sink(newValue.p.0) } // $ SPURIOUS: hasValueFlow=t11.2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment to explain why it should not flow in here?

// TODO: Check that 'expr' has a value type. Reference types don't cause writebacks.
isInWriteBackPosition(expr) and
// conservative value-type check
not forex(T::Type t | t = T::inferType(expr) | t.asClass().hasModifier("class"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
not forex(T::Type t | t = T::inferType(expr) | t.asClass().hasModifier("class"))
not forex(T::Type t | t = T::inferType(expr) | t.asClass().hasModifier(["class", "actor"]))

I feel it would make sense to factor into a predicate isReferenceType(Type t). It should also hold for type parameters bounded by a reference-type but feel free to defer that for later. There should just be a single place that owns this.

Comment on lines +20 to +21
// conservative value-type check
not forex(T::Type t | t = T::inferType(expr) | t.asClass().hasModifier("class"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense although I'd add a boolean parameter to isInWriteBackPosition to remember if it's in direct write-back position.

Comment on lines +94 to +97
name = p.getExternalNameNode().getValue()
or
not exists(p.getExternalNameNode()) and
name = "_"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're OK with a spurious setter call

@hvitved
hvitved requested a review from a team as a code owner October 29, 2026 12:43
@hvitved
hvitved requested a review from asgerf October 29, 2026 12:44

This branch has not been deployed

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

Labels

no-change-note-required This PR does not need a change note Unified

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants