@@ -5,6 +5,7 @@ import com.intellij.psi.PsiElement
5
5
import com.intellij.psi.util.findParentOfType
6
6
import com.intellij.psi.util.parentOfType
7
7
import com.intellij.refactoring.suggested.startOffset
8
+ import com.intellij.util.SmartList
8
9
import io.runescript.plugin.ide.RsBundle
9
10
import io.runescript.plugin.lang.psi.*
10
11
import io.runescript.plugin.lang.psi.refs.RsDynamicExpressionReference
@@ -107,6 +108,20 @@ class RsTypeInferenceVisitor(private val myInferenceData: RsTypeInference) : RsV
107
108
return this
108
109
}
109
110
111
+ private fun RsType?.flatten (): SmartList <RsType > {
112
+ if (this == null ) {
113
+ return SmartList ()
114
+ }
115
+ if (this is RsTupleType ) {
116
+ val result = SmartList <RsType >()
117
+ types.forEach {
118
+ result.addAll(it.flatten())
119
+ }
120
+ return result
121
+ }
122
+ return SmartList (this )
123
+ }
124
+
110
125
private fun Collection<RsType>?.fold (): RsType {
111
126
if (this == null ) {
112
127
return RsUnitType
@@ -117,10 +132,6 @@ class RsTypeInferenceVisitor(private val myInferenceData: RsTypeInference) : RsV
117
132
return RsTupleType (flatten())
118
133
}
119
134
120
- private fun checkTypeMismatchAll (context : PsiElement , actualType : RsType ? , expectedTypes : List <RsType >): Boolean {
121
- return expectedTypes.all { checkTypeMismatch(context, actualType, it, false ) }
122
- }
123
-
124
135
private fun checkTypeMismatch (
125
136
context : PsiElement ,
126
137
actualType : RsType ? ,
@@ -138,6 +149,26 @@ class RsTypeInferenceVisitor(private val myInferenceData: RsTypeInference) : RsV
138
149
if (unfoldedExpectedType is RsTupleType && RsErrorType in unfoldedExpectedType.types) {
139
150
return false
140
151
}
152
+ val flattenedActualType = unfoldedActualType.flatten()
153
+ val flattenedExpectedType = unfoldedExpectedType.flatten()
154
+ if (flattenedActualType.size != flattenedExpectedType.size
155
+ || ! flattenedActualType.zip(flattenedExpectedType).all { isSingleTypeMatch(it.second, it.first) }
156
+ ) {
157
+ if (reportError) {
158
+ context.error(
159
+ TYPE_MISMATCH_ERROR .format(
160
+ unfoldedActualType.representation,
161
+ unfoldedExpectedType.representation
162
+ )
163
+ )
164
+ }
165
+ return false
166
+ }
167
+ return true
168
+ }
169
+
170
+ private fun isSingleTypeMatch (unfoldedExpectedType : RsType , unfoldedActualType : RsType ): Boolean {
171
+ check(unfoldedActualType !is RsTupleType && unfoldedExpectedType !is RsTupleType )
141
172
if (unfoldedExpectedType == RsPrimitiveType .OBJ && unfoldedActualType == RsPrimitiveType .NAMEDOBJ ) {
142
173
// namedobj extends obj
143
174
return true
@@ -150,18 +181,7 @@ class RsTypeInferenceVisitor(private val myInferenceData: RsTypeInference) : RsV
150
181
// hooks are just strings that are parsed different.
151
182
return true
152
183
}
153
- if (unfoldedActualType != unfoldedExpectedType) {
154
- if (reportError) {
155
- context.error(
156
- TYPE_MISMATCH_ERROR .format(
157
- unfoldedActualType.representation,
158
- unfoldedExpectedType.representation
159
- )
160
- )
161
- }
162
- return false
163
- }
164
- return true
184
+ return unfoldedActualType == unfoldedExpectedType
165
185
}
166
186
167
187
override fun visitGosubExpression (o : RsGosubExpression ) {
@@ -598,6 +618,7 @@ class RsTypeInferenceVisitor(private val myInferenceData: RsTypeInference) : RsV
598
618
o.error(" Could not convert constant value '${value} ' to a long number." )
599
619
}
600
620
}
621
+
601
622
else -> {
602
623
val configReference = RsSymbolIndex .lookup(o.project, type, value)
603
624
if (configReference == null ) {
@@ -676,6 +697,7 @@ class RsTypeInferenceVisitor(private val myInferenceData: RsTypeInference) : RsV
676
697
?.toTypedArray<RsType >()
677
698
checkExpressionList(o, o.expressionList, expectedReturnList ? : emptyArray<RsType >())
678
699
}
700
+
679
701
companion object {
680
702
private const val TYPE_MISMATCH_ERROR = " Type mismatch: '%s' was given but '%s' was expected"
681
703
private const val INVALID_OPERATOR_ERROR = " Operator '%s' cannot be applied to '%s', '%s'"
0 commit comments