8000 Zzq/function contracts/cross package by lizard-boy · Pull Request #2 · greptileai/nilaway · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Zzq/function contracts/cross package #2

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

lizard-boy
Copy link
Collaborator

No description provided.

Copy link
@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

PR Summary

This PR refines the function contracts analysis by propagating cross‑package implications, updating result types, and adjusting trigger duplication and contract checking across modules.

• In assertion/analyzer.go, a new Implications field is added to Result and populated from the function analyzer.
• In accumulation/analyzer.go, ObservePackage now accepts both full triggers and implications.
• In assertion/function/assertiontree/parse_expr_producer.go, per‐return contract checks (RetHasContract) replace the previous HasContract.
• The function analyzer now duplicates triggers for contracted functions with new caching logic; note potential index bounds and strict type assertions.
• In functioncontracts/analyzer.go, upstream contracts are merged with local inference; consider using logger.error for panic recovery.

17 file(s) reviewed, 5 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +71 to +73
func (r *RootAssertionNode) ParamHasContract(funcObj *types.Func, i int) bool {
ctrt := r.getSingleNonnilToNonnilContract(funcObj)
return ctrt != nil && ctrt.Ins[i] == functioncontracts.NonNil
Copy link

Choose a reason for hiding this comment

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

logic: Ensure length of ctrt.Ins > i to avoid index out-of-range in ParamHasContract.

Suggested change
func (r *RootAssertionNode) ParamHasContract(funcObj *types.Func, i int) bool {
ctrt := r.getSingleNonnilToNonnilContract(funcObj)
return ctrt != nil && ctrt.Ins[i] == functioncontracts.NonNil
func (r *RootAssertionNode) ParamHasContract(funcObj *types.Func, i int) bool {
ctrt := r.getSingleNonnilToNonnilContract(funcObj)
return ctrt != nil && i < len(ctrt.Ins) && ctrt.Ins[i] == functioncontracts.NonNil

Comment on lines +77 to +80
// value.
func (r *RootAssertionNode) RetHasContract(funcObj *types.Func, i int) bool {
ctrt := r.getSingleNonnilToNonnilContract(funcObj)
return ctrt != nil && ctrt.Outs[i] == functioncontracts.NonNil
Copy link

Choose a reason for hiding this comment

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

logic: Add bounds check on ctrt.Outs in RetHasContract to prevent potential panic.

Suggested change
// value.
func (r *RootAssertionNode) RetHasContract(funcObj *types.Func, i int) bool {
ctrt := r.getSingleNonnilToNonnilContract(funcObj)
return ctrt != nil && ctrt.Outs[i] == functioncontracts.NonNil
// value.
func (r *RootAssertionNode) RetHasContract(funcObj *types.Func, i int) bool {
ctrt := r.getSingleNonnilToNonnilContract(funcObj)
return ctrt != nil && i < len(ctrt.Outs) && ctrt.Outs[i] == functioncontracts.NonNil

Comment on lines +104 to +110
getFuncID(pass, "learnUnderlyingFromOuterMakeInterface"): {
&FunctionContract{Ins: []ContractVal{NonNil}, Outs: []ContractVal{NonNil}},
},
getFuncID(pass, "ExportedFromInfer"): {
&FunctionContract{Ins: []ContractVal{NonNil}, Outs: []ContractVal{NonNil}},
},
getFuncID(pass, "twoCondsMerge"): {
Copy link

Choose a reason for hiding this comment

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

logic: Duplicate key 'ExportedFromInfer' in expected map; previous entry will be overwritten. Merge into one entry.

Suggested change
getFuncID(pass, "learnUnderlyingFromOuterMakeInterface"): {
&FunctionContract{Ins: []ContractVal{NonNil}, Outs: []ContractVal{NonNil}},
},
getFuncID(pass, "ExportedFromInfer"): {
&FunctionContract{Ins: []ContractVal{NonNil}, Outs: []ContractVal{NonNil}},
},
getFuncID(pass, "twoCondsMerge"): {
```suggestion getFuncID(pass, "learnUnderlyingFromOuterMakeInterface"): {
&FunctionContract{Ins: []ContractVal{NonNil}, Outs: []ContractVal{NonNil}},
},
getFuncID(pass, "twoCondsMerge"): {

Comment on lines +401 to 407
func (e *Engine) activateControlledImplications(site PrimitiveSite, siteExplained ExplainedBool) {
if controlledImpl, ok := e.controlledImplicationsBySite[site]; ok && siteExplained.Val() {
for impl := range controlledImpl {
e.processSingleExtraImplication(&impl)
}
}
}
Copy link

Choose a reason for hiding this comment

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

logic: Logic issue: In activateControlledImplications, the loop 'for impl := range controlledImpl' takes '&impl'. As the loop variable is reused, this will pass the address of the same variable in all iterations. Consider copying the value into a fresh variable before taking its address.

Suggested change
func (e *Engine) activateControlledImplications(site PrimitiveSite, siteExplained ExplainedBool) {
if controlledImpl, ok := e.controlledImplicationsBySite[site]; ok && siteExplained.Val() {
for impl := range controlledImpl {
e.processSingleExtraImplication(&impl)
}
}
}
func (e *Engine) activateControlledImplications(site PrimitiveSite, siteExplained ExplainedBool) {
if controlledImpl, ok := e.controlledImplicationsBySite[site]; ok && siteExplained.Val() {
for impl := range controlledImpl {
implCopy := impl // Create a new variable for each iteration
e.processSingleExtraImplication(&implCopy)
}
}
}

Comment on lines +202 to +208
// fullTrigger returns the primitive version of the full trigger.
func (p *Primitivizer) fullTrigger(trigger annotation.FullTrigger) PrimitiveFullTrigger {
// Expr is always nonnil, but our struct init analysis is capped at depth 1 so NilAway does not
// know this fact. Here, we explicitly guard against such cases to provide a hint.
if trigger.Consumer.Expr == nil {
panic(fmt.Sprintf("consume trigger %v has a nil Expr", trigger.Consumer))
}
Copy link

Choose a reason for hiding this comment

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

logic: Missing assignment to the Pos field in fullTrigger. Previously, it was set to trigger.Consumer.Expr.Pos() and later used for matching. Consider adding ‘Pos: trigger.Consumer.Expr.Pos(),’ in the returned struct literal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0