Skip to content

Commit

Permalink
named tuple enum variant inference, named tuple parameter info (#239)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkurnikov authored Nov 11, 2024
1 parent 5cc4caa commit 44bf143
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 46 deletions.
28 changes: 19 additions & 9 deletions src/main/kotlin/org/move/ide/hints/CallInfo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ class CallInfo(

companion object {
fun resolve(callExpr: MvCallExpr): CallInfo? {
val fn = callExpr.path.reference?.resolveFollowingAliases() as? MvFunction ?: return null
val msl = callExpr.isMsl()
val callTy = callExpr.inference(msl)?.getCallableType(callExpr) as? TyFunction ?: return null
return buildFunctionParameters(fn, callTy)
val item = callExpr.path.reference?.resolveFollowingAliases() ?: return null
return buildFunctionParameters(item, callTy)
}

fun resolve(assertMacroExpr: MvAssertMacroExpr): CallInfo {
Expand All @@ -43,14 +43,24 @@ class CallInfo(
return buildFunctionParameters(fn, callTy)
}

private fun buildFunctionParameters(function: MvFunction, ty: TyFunction): CallInfo {
val tys = ty.paramTypes.drop(if (function.isMethod) 1 else 0)
val params = function.parameters
.drop(if (function.isMethod) 1 else 0).map { it.name to it.type }
val self = function.selfParam?.let {
ty.paramTypes.firstOrNull()?.let { "self: ${tyToString(it)}" } ?: "_"
private fun buildFunctionParameters(item: MvElement, ty: TyFunction): CallInfo? {
return when (item) {
is MvFunction -> {
val tys = ty.paramTypes.drop(if (item.isMethod) 1 else 0)
val params = item.parameters
.drop(if (item.isMethod) 1 else 0).map { it.name to it.type }
val self = item.selfParam?.let {
ty.paramTypes.firstOrNull()?.let { "self: ${tyToString(it)}" } ?: "_"
}
CallInfo(self, buildParameters(tys, params))
}
is MvStruct, is MvEnumVariant -> {
// tuple struct
val tys = ty.paramTypes
CallInfo(null, tys.map { Parameter(null, null, it) })
}
else -> null
}
return CallInfo(self, buildParameters(tys, params))
}

private fun buildParameters(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ class CompositeParameterInfoHandler: ParameterInfoHandler<PsiElement, ParameterI
context.offset,
MvElementTypes.COMMA
)
// if (listElement.valueArgumentList.isEmpty()) {
// 0
// } else {
// }
}
context.setCurrentParameter(currentParameterIndex)
}
Expand Down
17 changes: 11 additions & 6 deletions src/main/kotlin/org/move/lang/core/types/infer/TyLowering.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ class TyLowering {
val explicitTypeParams = explicitTypeParamsSubst(methodOrPath, namedItem, msl)
baseTy.substitute(explicitTypeParams)
}
is MvEnumVariant -> lowerPath(methodOrPath, namedItem.enumItem, msl)
is MvEnumVariant -> {
// has to be MvPath of form `ENUM_NAME::ENUM_VARIANT_NAME`
val enumPath = (methodOrPath as? MvPath)?.qualifier ?: return TyUnknown
lowerPath(enumPath, namedItem.enumItem, msl)
}
else -> debugErrorOrFallback(
"${namedItem.elementType} path cannot be inferred into type",
TyUnknown
Expand All @@ -84,16 +88,17 @@ class TyLowering {

fun lowerCallable(
methodOrPath: MvMethodOrPath,
item: MvGenericDeclaration,
namedItem: MvGenericDeclaration,
parameterTypes: List<Ty>,
returnType: Ty,
msl: Boolean
): TyFunction {
val typeParamsSubst = item.typeParamsToTypeParamsSubst
val acqTypes = (item as? MvFunctionLike)?.acquiresPathTypes.orEmpty().map { it.loweredType(msl) }
val baseTy = TyFunction(item, typeParamsSubst, parameterTypes, returnType, acqTypes)
val acqTypes = (namedItem as? MvFunctionLike)?.acquiresPathTypes.orEmpty().map { it.loweredType(msl) }
val typeParamsSubst = namedItem.typeParamsToTypeParamsSubst

val baseTy = TyFunction(namedItem, typeParamsSubst, parameterTypes, returnType, acqTypes)

val explicitTypeParams = explicitTypeParamsSubst(methodOrPath, item, msl)
val explicitTypeParams = explicitTypeParamsSubst(methodOrPath, namedItem, msl)
return baseTy.substitute(explicitTypeParams) as TyFunction
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class TypeInferenceWalker(
TyUnknown
}
}
is MvEnumVariant -> item.enumItem.declaredType(ctx.msl)
is MvEnumVariant -> TyLowering().lowerPath(pathExpr.path, item, ctx.msl)
is MvModule -> TyUnknown
else -> debugErrorOrFallback(
"Referenced item ${item.elementType} " +
Expand Down Expand Up @@ -403,8 +403,7 @@ class TypeInferenceWalker(
is MvFieldsOwner -> {
val tupleFields = namedItem.tupleFields
if (tupleFields == null) return TyUnknown
val itemTy = instantiateTupleCallable(tupleFields, path, namedItem)
itemTy
instantiateTupleCallable(tupleFields, path, namedItem) ?: return TyUnknown
}
is MvPatBinding -> {
ctx.getBindingType(namedItem) as? TyLambda
Expand Down Expand Up @@ -594,34 +593,24 @@ class TypeInferenceWalker(

private fun instantiateTupleCallable(
tupleFields: MvTupleFields,
methodOrPath: MvMethodOrPath,
path: MvPath,
item: MvFieldsOwner
): TyFunction {
val genericItem = when (item) {
is MvStruct -> item
is MvEnumVariant -> item.enumItem
): TyFunction? {
val (genericItem, genericPath) = when (item) {
is MvStruct -> item to path
is MvEnumVariant -> {
val qualifierPath = path.qualifier ?: return null
item.enumItem to qualifierPath
}
else -> error("exhaustive")
}
//
val parameterTypes = tupleFields.tupleFieldDeclList.map { it.type.loweredType(msl) }
val returnType = genericItem.declaredType(msl)
val baseFuncTy =
TyLowering().lowerCallable(genericPath, genericItem, parameterTypes, returnType, msl)

val funcTy = TyLowering().lowerCallable(methodOrPath, genericItem, parameterTypes, returnType, msl)
//
// val baseTy = TyFunction(
// genericItem,
// genericItem.typeParamsToTypeParamsSubst,
// paramTypes = parameterTypes,
// returnType = returnType,
// acquiresTypes = emptyList(),
// )
//
// val explicitTypeParamsSubst = TyLowering().explicitTypeParamsSubst(methodOrPath, genericItem, msl)
// val funcTy = baseTy.substitute(explicitTypeParamsSubst)

// val baseTy = TyLowering().lowerTupleCallable(methodOrPath, item, tupleFields, msl)
val tyVarsSubst = genericItem.tyVarsSubst
return funcTy.substitute(tyVarsSubst) as TyFunction
return baseFuncTy.substitute(tyVarsSubst) as TyFunction
}

fun inferMacroCallExprTy(macroExpr: MvAssertMacroExpr): Ty {
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/org/move/lang/core/types/ty/TyFunction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,19 @@ data class TyFunction(
}
}

// do not account for explicit type arguments
// does not account for explicit type arguments
fun MvFunctionLike.functionTy(msl: Boolean): TyFunction = rawFunctionTy(this, msl)

private fun rawFunctionTy(item: MvFunctionLike, msl: Boolean): TyFunction {
val typeParamsSubst = item.typeParamsToTypeParamsSubst
val paramTypes = item.parameters.map { it.type?.loweredType(msl) ?: TyUnknown }
val acquiredTypes = item.acquiresPathTypes.map { it.loweredType(msl) }
val acqTypes = item.acquiresPathTypes.map { it.loweredType(msl) }
val retType = item.returnTypeTy(msl)
return TyFunction(
item,
typeParamsSubst,
paramTypes,
retType,
acquiredTypes,
acqTypes,
)
}
40 changes: 40 additions & 0 deletions src/test/kotlin/org/move/ide/hints/ParameterInfoHandlerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,44 @@ class ParameterInfoHandlerTest:
}
""", "_: bool, err: u64", 0
)

@MoveV2
fun `test parameter info for named tuple struct`() = checkByText("""
module 0x1::m {
struct S(u8, u16);
fun main() {
S(/*caret*/);
}
}
""", "u8, u16", 0)

@MoveV2
fun `test parameter info for generic named tuple struct`() = checkByText("""
module 0x1::m {
struct S<T>(T, T);
fun main() {
S<u8>(/*caret*/);
}
}
""", "u8, u8", 0)

@MoveV2
fun `test parameter info for named tuple enum variant`() = checkByText("""
module 0x1::m {
enum S { One(u8, u8) }
fun main() {
S::One(/*caret*/);
}
}
""", "u8, u8", 0)

@MoveV2
fun `test parameter info for generic named tuple enum variant`() = checkByText("""
module 0x1::m {
enum S<T> { One(T, T) }
fun main() {
S<u8>::One(/*caret*/);
}
}
""", "u8, u8", 0)
}
12 changes: 12 additions & 0 deletions src/test/kotlin/org/move/lang/types/CallableTypeTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.move.lang.types

import org.intellij.lang.annotations.Language
import org.move.ide.presentation.text
import org.move.lang.core.psi.MvCallExpr
import org.move.lang.core.psi.MvMethodCall
import org.move.lang.core.psi.ext.MvCallable
import org.move.lang.core.psi.ext.isMsl
Expand Down Expand Up @@ -54,6 +55,17 @@ class CallableTypeTest: TypificationTestCase() {
}
""")

fun `test function with explicit integer parameter callable type`() = testFunctionType("""
module 0x1::m {
fun call<T>(t: T): T { t }
fun main() {
call<u8>(1);
//^ fn(u8) -> u8
}
}
""")

private fun testFunctionType(@Language("Move") code: String) = testCallableType<MvCallExpr>(code)
private fun testMethodType(@Language("Move") code: String) = testCallableType<MvMethodCall>(code)

private inline fun <reified T: MvCallable> testCallableType(@Language("Move") code: String) {
Expand Down
36 changes: 36 additions & 0 deletions src/test/kotlin/org/move/lang/types/ExpressionTypesTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.move.lang.types

import org.move.utils.tests.MoveV2
import org.move.utils.tests.NamedAddress
import org.move.utils.tests.types.TypificationTestCase

Expand Down Expand Up @@ -2185,4 +2186,39 @@ module 0x1::main {
}
}
""")

@MoveV2
fun `test generic enum variant`() = testExpr("""
module 0x1::m {
enum S<T> { One }
fun main() {
let a = S<u8>::One;
a;
//^ 0x1::m::S<u8>
}
}
""")

@MoveV2
fun `test generic enum variant with positional fields`() = testExpr("""
module 0x1::m {
enum S<T> { One(T, T) }
fun main() {
let a = S<u8>::One(1, 1);
a;
//^ 0x1::m::S<u8>
}
}
""")

fun `test function with explicit integer parameter return type`() = testExpr("""
module 0x1::m {
fun call<T>(t: T): T { t }
fun main() {
let a = call<u8>(1);
a;
//^ u8
}
}
""")
}

0 comments on commit 44bf143

Please sign in to comment.