Skip to content

Commit

Permalink
fix: bug where compilers output selection wasn't updating when source…
Browse files Browse the repository at this point in the history
…s changes compiler (#2089)
  • Loading branch information
antazoey authored May 13, 2024
1 parent 26bec8b commit 5b0bd21
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 12 deletions.
20 changes: 13 additions & 7 deletions src/ape/api/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ def add_compiler_data(self, compiler_data: Sequence[Compiler]) -> List[Compiler]
)

for given_compiler in given_compilers:
other_given_compilers = [c for c in given_compilers if c != given_compiler]
if not (other_given_compilers := [c for c in given_compilers if c != given_compiler]):
continue

contract_types_from_others = [
n for c in other_given_compilers for n in (c.contractTypes or [])
]
Expand All @@ -224,15 +226,12 @@ def add_compiler_data(self, compiler_data: Sequence[Compiler]) -> List[Compiler]
raise ProjectError(f"Contract type(s) '{collide_str}' collision across compilers.")

new_types = [n for c in given_compilers for n in (c.contractTypes or [])]

# Merge given compilers with existing compilers.
existing_compilers = self.manifest.compilers or []

# Existing compilers remaining after processing new compilers.
remaining_existing_compilers: List[Compiler] = []

for existing_compiler in existing_compilers:
find_iter = iter(x for x in compiler_data if x == existing_compiler)
# NOTE: For compilers to be equal, their name, version, and settings must be equal.
find_iter = (x for x in compiler_data if x == existing_compiler)

if matching_given_compiler := next(find_iter, None):
# Compiler already exists in the system, possibly with different contract types.
Expand All @@ -243,6 +242,7 @@ def add_compiler_data(self, compiler_data: Sequence[Compiler]) -> List[Compiler]
*(matching_given_compiler.contractTypes or []),
}
)

# NOTE: Purposely we don't add the existing compiler back,
# as it is the same as the given compiler, (meaning same
# name, version, and settings), and we have
Expand All @@ -258,10 +258,16 @@ def add_compiler_data(self, compiler_data: Sequence[Compiler]) -> List[Compiler]

# Clear output selection for new types, since they are present in the new compiler.
if existing_compiler.settings and "outputSelection" in existing_compiler.settings:
new_src_ids = {
(self.manifest.contract_types or {})[x].source_id
for x in new_types
if x in (self.manifest.contract_types or {})
and (self.manifest.contract_types or {})[x].source_id is not None
}
existing_compiler.settings["outputSelection"] = {
k: v
for k, v in existing_compiler.settings["outputSelection"].items()
if k not in new_types
if k not in new_src_ids
}

# Remove compilers without contract types.
Expand Down
20 changes: 15 additions & 5 deletions tests/functional/test_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -651,21 +651,21 @@ def test_add_compiler_data(project_with_dependency_config):
name="comp",
version="1.0.0",
contractTypes=["foo"],
settings={"outputSelection": {"foo": "*"}},
settings={"outputSelection": {"path/to/Foo.sol": "*"}},
)
compiler_2 = Compiler(
name="test",
version="2.0.0",
contractTypes=["bar", "stay"],
settings={"outputSelection": {"bar": "*", "stay": "*"}},
settings={"outputSelection": {"path/to/Bar.vy": "*", "stay.vy": "*"}},
)

# NOTE: Has same contract as compiler 2 and thus replaces the contract.
compiler_3 = Compiler(
name="test",
version="3.0.0",
contractTypes=["bar"],
settings={"outputSelection": {"bar": "*"}},
settings={"outputSelection": {"path/to/Bar.vy": "*"}},
)

proj = project.local_project
Expand All @@ -675,6 +675,16 @@ def test_add_compiler_data(project_with_dependency_config):
first_exp = [*start_compilers, compiler]
final_exp = [*first_exp, compiler_2]

# Ensure types are in manifest for type-source-id lookup.
bar = ContractType(contractName="bar", sourceId="path/to/Bar.vy")
foo = ContractType(contractName="foo", sourceId="path/to/Foo.sol")
proj._cached_manifest = PackageManifest(
contractTypes={"bar": bar, "foo": foo},
sources={"path/to/Bar.vy": Source(), "path/to/Foo.vy": Source()},
)
proj._contracts = proj._cached_manifest.contract_types
assert proj.cached_manifest.contract_types, "Setup failed - need manifest contract types"

# Add twice to show it's only added once.
proj.add_compiler_data(argument)
proj.add_compiler_data(argument)
Expand All @@ -689,10 +699,10 @@ def test_add_compiler_data(project_with_dependency_config):
proj.add_compiler_data(third_arg)
comp = [c for c in proj.manifest.compilers if c.name == "test" and c.version == "2.0.0"][0]
assert "bar" not in comp.contractTypes
assert "bar" not in comp.settings["outputSelection"]
assert "path/to/Bar.vy" not in comp.settings["outputSelection"]
new_comp = [c for c in proj.manifest.compilers if c.name == "test" and c.version == "3.0.0"][0]
assert "bar" in new_comp.contractTypes
assert "bar" in new_comp.settings["outputSelection"]
assert "path/to/Bar.vy" in new_comp.settings["outputSelection"]

# Show that compilers without contract types go away.
(compiler_3.contractTypes or []).append("stay")
Expand Down

0 comments on commit 5b0bd21

Please sign in to comment.