Skip to content
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

correctly handle case where module has the same name as named address #274

Merged
merged 2 commits into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,21 @@ class MvUnresolvedReferenceInspection: MvLocalInspectionTool() {
// attribute values are special case
if (path.hasAncestor<MvAttrItem>()) return

// val pathReference = path.reference ?: return
val pathKind = path.pathKind()
when (pathKind) {
is NamedAddress, is ValueAddress -> return
is NamedAddressOrUnqualifiedPath, is NamedAddress, is ValueAddress -> return
is UnqualifiedPath -> tryMultiResolveOrRegisterError(path, holder)
is QualifiedPath -> {
if (pathKind !is QualifiedPath.Module) {
val qualifier = pathKind.qualifier
// qualifier is unresolved, no need to resolve current path
if (qualifier.reference?.resolve() == null) return
when (pathKind) {
is QualifiedPath.ModuleItem,
is QualifiedPath.FQModuleItem,
is QualifiedPath.UseGroupItem,
is QualifiedPath.ModuleOrItem -> {
val qualifier = pathKind.qualifier
// qualifier is unresolved, no need to resolve current path
if (qualifier.reference?.resolve() == null) return
}
else -> Unit
}
tryMultiResolveOrRegisterError(path, holder)
}
Expand Down
10 changes: 1 addition & 9 deletions src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,7 @@ val MvModule.friendModules: Sequence<MvModule>
get() {
return this.friendDeclList
.asSequence()
.mapNotNull { it.path?.reference?.resolveFollowingAliases() as? MvModule }
// return sequence {
// }
// val friends = mutableSetOf<MvModule>()
// for (modulePath in friendModulePaths) {
// val module = modulePath.reference?.resolveFollowingAliases() as? MvModule ?: continue
// friends.add(module)
// }
// return friends
.mapNotNull { it.path.reference?.resolveFollowingAliases() as? MvModule }
}

fun MvModule.allFunctions(): List<MvFunction> {
Expand Down
31 changes: 20 additions & 11 deletions src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ sealed class PathKind {
override val ns: Set<Namespace> get() = NONE
}

// aptos_std:: where aptos_std is a existing named address in a project
data class NamedAddressOrUnqualifiedPath(
val address: Address.Named,
override val ns: Set<Namespace>
): PathKind()

// 0x1::
data class ValueAddress(val address: Address.Value): PathKind() {
override val ns: Set<Namespace> get() = NONE
Expand All @@ -35,10 +41,14 @@ sealed class PathKind {
val qualifier: MvPath,
override val ns: Set<Namespace>
): PathKind() {
// `0x1:foo` or `aptos_framework::foo` (where aptos_framework is known named address)
// `0x1:foo`
class Module(path: MvPath, qualifier: MvPath, ns: Set<Namespace>, val address: Address):
QualifiedPath(path, qualifier, ns)

// `aptos_framework::foo` (where aptos_framework is known named address, but it can still be a module)
class ModuleOrItem(path: MvPath, qualifier: MvPath, ns: Set<Namespace>, val address: Address):
QualifiedPath(path, qualifier, ns)

// bar in foo::bar, where foo is not a named address
class ModuleItem(path: MvPath, qualifier: MvPath, ns: Set<Namespace>):
QualifiedPath(path, qualifier, ns)
Expand Down Expand Up @@ -96,7 +106,7 @@ fun MvPath.pathKind(isCompletion: Boolean = false): PathKind {
if (this.isColonColonNext) {
val namedAddress = moveProject.getNamedAddressTestAware(referenceName)
if (namedAddress != null) {
return PathKind.NamedAddress(namedAddress)
return PathKind.NamedAddressOrUnqualifiedPath(namedAddress, MODULES)
}
}
}
Expand All @@ -107,6 +117,7 @@ fun MvPath.pathKind(isCompletion: Boolean = false): PathKind {
}

val qualifierOfQualifier = qualifier.path
val ns = this.allowedNamespaces(isCompletion)

// two-element paths
if (qualifierOfQualifier == null) {
Expand All @@ -123,26 +134,24 @@ fun MvPath.pathKind(isCompletion: Boolean = false): PathKind {
// ^
moveProject != null && qualifierItemName != null -> {
val namedAddress = moveProject.getNamedAddressTestAware(qualifierItemName)
if (namedAddress != null) {
// known named address, can be module path
return PathKind.QualifiedPath.Module(this, qualifier, MODULES, namedAddress)
if (this.isUseSpeck) {
val address =
namedAddress ?: Address.Named(qualifierItemName, null)
return PathKind.QualifiedPath.Module(this, qualifier, MODULES, address)
}
// `use std::main`
// ^
// , where std is the unknown named address
if (this.isUseSpeck) {
val address = Address.Named(qualifierItemName, null)
return PathKind.QualifiedPath.Module(this, qualifier, MODULES, address)
if (namedAddress != null) {
// known named address, can be module path, or module item path too
return PathKind.QualifiedPath.ModuleOrItem(this, qualifier, MODULES + ns, namedAddress)
}
}
}
// module::name
// ^
val ns = this.allowedNamespaces(isCompletion)
return PathKind.QualifiedPath.ModuleItem(this, qualifier, ns)
}

// three-element path
val ns = this.allowedNamespaces(isCompletion)
return PathKind.QualifiedPath.FQModuleItem(this, qualifier, ns)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import org.move.lang.core.resolve.*
import org.move.lang.core.resolve.ref.*
import org.move.lang.core.resolve.ref.Namespace.*
import org.move.lang.core.resolve2.*
import org.move.lang.core.resolve2.PathKind.NamedAddress
import org.move.lang.core.resolve2.PathKind.ValueAddress
import org.move.lang.core.types.infer.inference
import org.move.lang.core.types.ty.Ty
Expand Down Expand Up @@ -151,8 +150,8 @@ fun processPathResolveVariants(
processor: RsResolveProcessor
): Boolean {
return when (pathKind) {
is NamedAddress, is ValueAddress -> false
is PathKind.UnqualifiedPath -> {
is PathKind.NamedAddress, is ValueAddress -> false
is PathKind.NamedAddressOrUnqualifiedPath, is PathKind.UnqualifiedPath -> {
if (MODULE in pathKind.ns) {
// Self::
if (processor.lazy("Self", MODULES) { ctx.containingModule }) return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -576,4 +576,25 @@ module 0x1::m {
}
}
""")

@NamedAddress("uq64x64", "0x1")
fun `test no error on module for unresolved module if the same name as address`() = checkByText("""
module 0x1::m {
fun main() {
uq64x64::call();
}
}
""")

@NamedAddress("uq64x64", "0x2")
fun `test error on known item of module with the same name as address`() = checkByText("""
module uq64x64::uq64x64 {
}
module 0x1::m {
use uq64x64::uq64x64;
fun main() {
uq64x64::<error descr="Unresolved function: `call`">call</error>();
}
}
""")
}
110 changes: 110 additions & 0 deletions src/test/kotlin/org/move/lang/resolve/ResolveItemsTreeProjectTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -543,4 +543,114 @@ module 0x1::main {
""")
}
}

fun `test resolve module that has the same name as address`() = checkByFileTree {
moveToml("""
[package]
name = "Main"

[dependencies]
UQ64x64 = { local = "./uq64x64" }
""")
sources {
main("""
module 0x1::m {
use uq64x64::uq64x64;
//^
}
""")
}
dir("uq64x64") {
moveToml("""
[package]
name = "UQ64x64"

[addresses]
uq64x64 = "0x4e9fce03284c0ce0b86c88dd5a46f050cad2f4f33c4cdd29d98f501868558c81"
""")
sources {
move("uq64x64.move", """
module uq64x64::uq64x64 {
//X
}
""")
}
}
}

fun `test resolve module in path from module that has the same name as address`() = checkByFileTree {
moveToml("""
[package]
name = "Main"

[dependencies]
UQ64x64 = { local = "./uq64x64" }
""")
sources {
main("""
module 0x1::m {
use uq64x64::uq64x64;
fun main() {
uq64x64::call();
//^
}
}
""")
}
dir("uq64x64") {
moveToml("""
[package]
name = "UQ64x64"

[addresses]
uq64x64 = "0x4e9fce03284c0ce0b86c88dd5a46f050cad2f4f33c4cdd29d98f501868558c81"
""")
sources {
move("uq64x64.move", """
module uq64x64::uq64x64 {
//X
public fun call() {}
}
""")
}
}
}

fun `test resolve function from module that has the same name as address`() = checkByFileTree {
moveToml("""
[package]
name = "Main"

[dependencies]
UQ64x64 = { local = "./uq64x64" }
""")
sources {
main("""
module 0x1::m {
use uq64x64::uq64x64;
fun main() {
uq64x64::call();
//^
}
}
""")
}
dir("uq64x64") {
moveToml("""
[package]
name = "UQ64x64"

[addresses]
uq64x64 = "0x4e9fce03284c0ce0b86c88dd5a46f050cad2f4f33c4cdd29d98f501868558c81"
""")
sources {
move("uq64x64.move", """
module uq64x64::uq64x64 {
public fun call() {}
//X
}
""")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ class ResolveModulesTest : ResolveTestCase() {
fun `test resolve friend module with named address`() = checkByCode("""
module aptos_std::myfriend {}
//X
module 0x1::main {
module aptos_std::main {
friend aptos_std::myfriend;
//^
}
Expand Down
Loading